> ## Client identification
>
> Requests to this API should include a `Client-Platform` header alongside
> `Authorization`, identifying the application, tool, or model making the
> request. This is used for integration support and analytics.
>
> Use your model or tool name, for example `claude-code` or `chatgpt`.
>
> Example:
>
> ```bash
> curl https://api.salaryboxapp.com/... \
>   -H "Authorization: Api-Key <api-key>" \
>   -H "Client-Platform: claude-code"
> ```

# Conventions

Every endpoint follows these rules unless its own page says otherwise.
[Endpoint differences](/endpoint-differences) lists the exceptions in one place.

## Responses

A successful response is `200` with this envelope:

```json
{
  "message": "Success",
  "status": true,
  "data": [],
  "count": 0,
  "prev": null,
  "next": null
}
```

`count`, `prev` and `next` appear only on paginated endpoints. Endpoints that return one object
(such as Get Company Profile) put it directly in `data`.

## Pagination

* Send `page` (from 1) and `page_size`. `page_size` defaults to the endpoint's maximum, usually 500.
* A larger `page_size` is reduced to the maximum. A zero, negative or non-numeric value falls back to the default.
* `count` is the total number of results across all pages. `next` / `prev`: URL of the next / previous page, or `null`.
* A page past the last one returns `404` with `"message": "Invalid page."`.
* Endpoints that group results by staff member (for example List Attendance Timesheets or List Payroll Payments) count pages and `count` in **staff members**, not in the items nested under them. One person's items are never split across pages.
* Results are in a stable order, so it is safe to page through them.

## Filters

* **Repeatable parameters** are sent once per value: `salarybox_ids=SBK7Q2M9TX&salarybox_ids=SBK3H8D1LP`. A comma-separated value is treated as one value and matches nothing, except on the few endpoints that take comma-separated lists, and on List Staff and List Inactive Staff, which reject it with `400`. See [Endpoint differences](/endpoint-differences).
* Within one filter, a result matches if it matches **any** value. Different filters combine with **AND**.
* Names (branch, department, job title) must match exactly, including case and spaces.
* IDs or names that match nobody are ignored. If nothing matches, you get `200` with an empty `data` and `count` 0.
* Unknown query parameters are ignored.

## Dates and times

* Dates are `YYYY-MM-DD` and months are `YYYY-MM`. A date range includes both `start_date` and `end_date`, and `end_date` cannot be before `start_date`.
* Dates are whole days in your company's time zone (`time_zone` in Get Company Profile), unless an endpoint says otherwise.
* Date-times are ISO 8601 with a UTC offset. Punch times are in the staff member's time zone.
* Night shifts: a punch after midnight belongs to the day the shift started.
* Amounts and hours are strings with 2 decimals, for example `"1250.00"` or `"1.55"`.

## Who is included

* **Staff** means everyone in your company except company admins and accountants. Branch admins and managers are staff.
* Company admins never appear in staff results. Use List Admins for them.
* Deleted staff never appear. Inactive staff appear only where an endpoint says so; [Endpoint differences](/endpoint-differences#who-is-included) lists which.
* Unless stated otherwise, staff are ordered by when they were added to SalaryBox, oldest first.

## Request statuses

The request endpoints (`/pending-requests/leave`, `/pending-requests/reimbursements` and
`/pending-requests/new-joinees`) return only requests waiting for a decision by default. Send
`status` to read decided ones too. `/pending-requests/device-mapping` takes no `status`: it always
returns only requests waiting for approval.

| Filter value         | Status on each item  | Meaning                                                                            |
| -------------------- | -------------------- | ---------------------------------------------------------------------------------- |
| `current` (default)  | `pending`            | Waiting for a decision.                                                            |
| `approved`           | `approved`           | Approved.                                                                          |
| `partially_approved` | `partially_approved` | Leave only: approved with day-by-day changes.                                      |
| `declined`           | `declined`           | Rejected by an approver before it was approved.                                    |
| `cancelled`          | `cancelled`          | Withdrawn by the staff member while it was pending. Leave and reimbursements only. |
| `revoked`            | `revoked`            | Approved, then reversed by an admin. Leave and reimbursements only.                |
| `all`                | any of the above     | Every request.                                                                     |

The filter for waiting requests is `current`, but such requests show `pending` as their status.

## Data freshness

The CRM endpoints and List Latest Staff Locations can be a few seconds behind the app.