{"auth":{"bearer":[{"key":"token","type":"string","value":"{{api_token}}"}],"type":"bearer"},"info":{"description":"The Sona Client API provides programmatic access to manage workforce operations including users, shifts, absences, employment periods, and organisational structures.\n\n## Key Concepts\n\n### Authentication\n\nAll requests require a Bearer token in the `Authorization` header. Tokens are scoped to an organisation and issued by the Sona team during integration setup — there is no self-service token endpoint. Contact your Sona representative if you need a new token or if your token has been revoked.\n\n### API Token Permissions & 403 Errors\n\nAPI tokens can be configured with an allowed list of endpoints. If your token is restricted and you attempt to access an endpoint not in the allowed list, the API will return a `403 Forbidden` response with the message: *\"This API credential does not have access to this endpoint\"*. Contact Sona to have the required endpoint(s) added to your token's permissions.\n\nA token with no explicit endpoint restrictions has access to all endpoints.\n\n### Identifiers: Sona IDs vs External IDs (`idx`)\n\nEvery resource has a Sona-generated UUID (`id`). Most resources also accept an **external identifier** (`idx` or `external_id`) that you control. This lets you reference resources using your own system's IDs without storing Sona's UUIDs.\n\nWhere an endpoint accepts `{user_id_or_idx}` in the path, you can pass either. For org unit references in request bodies, pass `{ \"id\": \"<sona_id>\" }` or `{ \"idx\": \"<your_external_id>\" }`.\n\nWe strongly recommend setting `external_id` / `idx` on every resource you create — it simplifies lookups and avoids the need to maintain an ID mapping table.\n\n### Pagination\n\nList endpoints return paginated results. Use `page` (1-indexed, not `page_number`) and `page_size` query parameters. The default page size is 10. Responses include `page_number`, `page_size`, `total_pages`, and `total_entries` alongside the `entries` array.\n\n### Errors\n\nThe API returns two error shapes. **Non-validation errors** (400, 401, 403, 404, 409, 500) return `{ \"error\": \"Not Found\", \"message\": \"...\" }`. **Validation errors** (422) on create/update usually return `{ \"errors\": { \"field_name\": [\"error message\", ...] } }` with per-field error arrays, but some 422s (a request that is well-formed but not allowed, or invalid query parameters) use the `{ \"error\", \"message\" }` shape instead. Each endpoint's 422 response names the schema it returns; when handling a 422 generically, check for `errors` first and fall back to `message`. The metrics endpoints are an exception: their errors are `{ \"error\": \"...\" }` with no `message`.\n\nEvery endpoint can return `401` (missing or invalid token) and `403` (the token is restricted to other endpoints) before the request is processed.\n\n### Date and Time Formats\n\nThe API uses **ISO 8601** throughout:\n\n- **Datetimes** are UTC with format `YYYY-MM-DDTHH:mm:ssZ` — e.g. `2025-03-15T14:30:00Z`. Always include the trailing `Z` (UTC timezone designator). Datetimes without a timezone are rejected.\n- **Dates** use format `YYYY-MM-DD` — e.g. `2025-03-15`. Used for fields like `start_date`, `finish_date`, and `final_date_of_employment`.\n\nAll timestamps returned by the API (`inserted_at`, `updated_at`, shift times, etc.) are in UTC. They end in `Z`, with one exception: `inserted_at` and `updated_at` on org attributes and org unit attributes are UTC but have no designator (e.g. `2025-03-15T14:30:00`). Treat a datetime without a designator as UTC.\n\n### Incremental Sync\n\nIf you are building an ongoing sync rather than a one-off import, use the `updated_at` query parameter on list endpoints to fetch only records that have changed since your last sync. Currently supported on:\n\n- `GET /api/v1/users?updated_at=2025-03-15T10:00:00Z`\n- `GET /api/v1/employment_periods?updated_at=2025-03-15T10:00:00Z`\n- `GET /api/v1/services?updated_at=2025-03-15T10:00:00Z` (a service counts as changed when the service itself, its config or one of its demand periods was updated, or when anything was added to its audit log, which covers removed demand periods)\n- `GET /api/v1/people_we_support?updated_at=2025-03-15T10:00:00Z` (the person's own record; status and care package changes do not count)\n- `GET /api/v1/care_packages?updated_at=2025-03-15T10:00:00Z` (also on `GET /api/v1/people_we_support/{id}/care_packages`). A package counts as updated when it changes, including being ended by a newer package, or when any of its hour lines gets a new approval status. This is the way to sync approvals: each package comes back with its lines' current statuses, so you don't need a call per hour line.\n- `GET /api/v1/status_records?updated_at=2025-03-15T10:00:00Z` (also on `GET /api/v1/people_we_support/{id}/status_records`). Every person's active/inactive history; a record counts as updated when it is created or changed, including being ended by a newer record.\n\nThis returns all records updated on or after the given timestamp. Store the timestamp of each successful sync and pass it on the next run to avoid re-processing unchanged records. Combine with pagination to handle large result sets.\n\n### Reference Data\n\nSeveral resources act as configuration that must exist before you can create users or employment periods. These are typically set up by the Sona team during onboarding, but can be retrieved via the API:\n\n| Resource | Endpoint | Used by |\n|----------|----------|---------|\n| Org Units | `GET /api/v1/org_units` | Users, Employment Periods |\n| Levels | `GET /api/v1/levels` | Employment Periods |\n| Contract Types | `GET /api/v1/contract_types` | Employment Periods (via Employment Specs) |\n| Jobs | `GET /api/v1/jobs` | Employment Periods |\n| Permission Roles | `GET /api/v1/permission_roles` | Employment Periods |\n| Shift Types | `GET /api/v1/shift_types` | Shifts |\n| Absence Types | `GET /api/v1/absence_types` | Absences |\n| Termination Reasons | `GET /api/v1/termination_reasons` | Employment Periods (termination) |\n| Metrics | `GET /api/v1/metrics` | Metric Values |\n\nFetch these first to obtain the IDs you will need when creating users and employment periods.\n\n### User lookup\n\n`GET /api/v1/users/lookup` resolves **one** user from **one** identity parameter (`insurance_number`, `employee_number`, `external_id`, `contact_email`, or `email`). The response includes that user, their employment periods (up to 200), and which parameter was used (`lookup.by`). See **Responses** on the endpoint for status codes.\n\n---\n\n## Common Workflows\n\n### Creating a User with an Employment Period\n\nA **User** represents a person in the system. An **Employment Period** represents a specific period of employment for that user (start date, contract type, org unit, etc.). Most integrations create both together.\n\n**Prerequisites:** Before creating a user you will need an org unit ID (from `GET /api/v1/org_units`). If creating an employment period, you will also need IDs for the level, contract type, and optionally the job — see the Reference Data table above.\n\n**Option A — Single request with `create_employment_period`**\n\nSet `create_employment_period: true` on `POST /api/v1/users` to create the user and a minimal employment period in one call. You must also supply `administrative_org_unit`. Optionally pass `employment_period_params` to configure the employment period (start date, employee number, level, etc.).\n\n**Important:** This option places the user into the Sona **onboarding flow**. Your Sona instance must have onboarding configured for this to work correctly. If your organisation does not use Sona's onboarding feature, use Option B instead.\n\n**Option B — Two separate requests**\n\n1. `POST /api/v1/users` — create the user (returns a `user_id`).\n2. `POST /api/v1/employment_periods` — create the employment period, referencing the `user_id` from step 1. This requires `user_id`, `start_date`, and an `employment_specs` array containing at least one entry with `contract_types`, `rates_of_pay`, and `contracted_hours`.\n\nUse Option B when you need full control over the employment period configuration or when your Sona instance does not have onboarding enabled.\n\n**Updating a user**\n\n`PUT /api/v1/users/{user_id}` updates user fields. Only the fields you include in the request body are changed — omitted fields are left untouched.\n\n**Granting manager access**\n\nTo make a user a manager, grant access to specific org units via `manager_org_units` (full read/write) or `read_only_org_units` (read only). A user also needs a **base role** on `user.roles` to be able to log in to the manager desktop — if you grant manager access without passing `base_roles`, Sona will automatically assign `manager` (or `read_only_manager` if only read-only access is granted) so the user can log in. Existing roles are never overwritten. Pass `base_roles` explicitly to override the default or to assign a more specific role (e.g. `hr_manager`, `payroll_manager`).\n\n---\n\n### Terminating and Undoing Termination\n\n**Prerequisites:** Termination requires the **leaver workflow** to be enabled on your Sona instance. If it is not enabled, the terminate endpoint will return a 422 error. Contact your Sona representative to enable it. If your organisation uses termination reasons, retrieve available reasons from your Sona configuration beforehand.\n\n**Terminating a user**\n\n`PUT /api/v1/users/{user_id_or_idx}/terminate` ends a user's employment. You can identify the user by their Sona ID or external ID. The only required field is `final_date_of_employment`; you can optionally provide a termination reason and details. See the endpoint documentation for accepted parameters.\n\nAfter termination the user's `state` transitions through: `active` → `leaver` (between the request and the final date) → `left` (after the final date). Shifts beyond the final date are automatically removed.\n\n**Undoing a termination**\n\nIf a termination was made in error, reverse it with `PUT /api/v1/users/{user_id_or_idx}/undo_termination`. No request body is required — the user's state is restored to `active` and the final date of employment is cleared.\n\n---\n\n### Rehiring a former employee\n\n**Prerequisites:** A **completed** previous employment period with a **finish date** must already exist in your organisation. You need **non-continuous employment periods** enabled if the **same employee number** has a **gap** between the old period’s end and the new period’s start. Otherwise those periods must be **continuous** (back-to-back). Contact Sona to confirm this setting if you see validation errors about continuity or about starting a new period after a termination.\n\nA **rehire** is a **new** employment period for someone whose **previous** period **ended** with a **finish date**, and who is **no longer active** with **`final_date_of_employment`** set and state **`left`**. You use a rehire when the person returns after a real exit. **`undo_termination`** corrects a mistaken termination while the employee is still a **leaver**, but **has not left** yet. **Do not** use **`undo_termination`** for a genuine return after employment has ended. **Do** create a new employment period.\n\n**`termination_would_rehire`:** On the **previous** employment period, if this has been set to **`false`**, it means the person is **not suitable for rehire** (do-not-rehire). The Client API does **not** reject a new `POST /api/v1/employment_periods` when this value is **`false`**. You must enforce do-not-rehire in your integration if your policy requires it.\n\n**Creating the new period**\n\nCall `POST /api/v1/employment_periods` for an **existing** user.\n\nSona **derives** **`is_rehire`** on the new period unless you set it yourself. It is **true** only when **all** of the following hold: at least one **other** employment period is **finished**; **`final_date_of_employment`** is set; the user is **`leaver`** or **`left`** (see **Terminating a user** above); and the **new** period’s **`finish_date`** is **unset** or **strictly after** today. If **`finish_date`** on the new period is **today** or **earlier**, **`is_rehire`** is not derived as true, so rehire cleanup does not run—**`final_date_of_employment`** stays set and the user is not reactivated.\n\n**What happens when `is_rehire` is true after create**\n\n**`forces_new_holiday_breakdown`** defaults to **`true`** unless you set it (see the employment period parameters in this spec). Sona clears **`final_date_of_employment`**. Sona sets the user’s state to **`active`**.\n\n**Payroll note:** A termination and rehire **within the same pay period** can require special handling in Sona (for example pay or average-pay splits). If you use integrated payroll and hit edge cases, work with Sona to align behaviour.\n\n---\n\n### Custom Forms and Entries\n\n**Custom Forms** define the structure (fields, validation rules) for collecting additional data about users — for example employee documents, onboarding checklists, or qualifications. **Custom Form Entries** are submitted instances of those forms.\n\n**Prerequisites:** Custom forms are configured by the Sona team for your organisation. The form structure — including field names, accepted values, required fields, and validation rules — is defined during this setup and cannot be changed via the API. Contact your Sona representative if you need a new form or changes to an existing one.\n\n**Step 1 — Discover available forms**\n\n`GET /api/v1/custom_forms` returns all custom forms configured for your organisation. Each form has a unique `id` and describes the fields an entry must include. Use this to determine the `custom_form_id` and the exact field names you need to supply when creating entries.\n\n**Step 2 — Create an entry**\n\n`POST /api/v1/custom_form_entries` with `custom_form_id`, `user_id`, and the field values defined by the form. The required and optional fields vary per form — refer to the form definition from Step 1. File fields can be uploaded via multipart form-data or as base64-encoded JSON (see the endpoint documentation for upload formats and size limits).\n\n**Step 3 — View entries**\n\n`GET /api/v1/custom_form_entries` lists all entries (paginated). Use `GET /api/v1/custom_form_entries/{id}` to retrieve a single entry.\n\n---\n\n## Webhooks\n\nSona supports real-time webhook notifications for 25 event types covering users, employment, absences, shifts, amendments, jobs, and agency shifts.\n\n**[View the full Webhooks Guide](webhooks/)** for delivery format, HMAC-SHA256 signature verification, all event types, and payload schemas.\n\nTo manage subscriptions, see the **Webhook Subscriptions** endpoints in the sidebar.\n","name":"Sona Client API","schema":"https://schema.getpostman.com/json/collection/v2.1.0/collection.json","version":"1.14"},"item":[{"description":null,"item":[{"name":"Get a list of absences","request":{"description":"List all absences for the current organisation.","header":[],"method":"GET","url":{"host":["{{base_url}}"],"path":["api","v1","absences"],"query":[{"description":"Number of elements per page","disabled":true,"key":"page_size","value":""},{"description":"Number of the page","disabled":true,"key":"page","value":""},{"description":"Filter by user id. If omitted all absences are returned.","disabled":true,"key":"user_id","value":""},{"description":"Filter by external user id. If omitted all absences are returned.","disabled":true,"key":"user_idx","value":""},{"description":"Filter by absence type id. If omitted all absences are returned.","disabled":true,"key":"absence_type_id","value":""},{"description":"order by starts at DESC if provided starts_at_desc","disabled":true,"key":"order_by","value":""},{"description":"When true, each linked/unlinked shift will include a payroll_run_rows array with the raw payroll run row data (start_datetime, end_datetime, duration_in_minutes, entry_type, pay_type, variant). Use this when you need the payroll-authoritative datetimes rather than the scheduled shift times.","disabled":true,"key":"include_payroll_run_rows","value":""}],"raw":"{{base_url}}/api/v1/absences","variable":[]}}},{"name":"Create a new absence","request":{"body":{"mode":"raw","options":{"raw":{"language":"json"}},"raw":"{\n  \"absence_subtype_id\": \"dbad14a0-e789-4d85-a5e2-1c8a4f1918ed\",\n  \"absence_type_id\": \"9f8bda89-002a-45e0-8660-46e2fff714d2\",\n  \"create_replacement_shifts\": false,\n  \"ends_at\": \"2019-04-20T15:47:58+00:00\",\n  \"idx\": \"some-external-id\",\n  \"is_open_ended\": false,\n  \"sick_note_provided\": false,\n  \"starts_at\": \"2019-04-20T07:47:58+00:00\",\n  \"user_id\": \"9f8bda89-002a-45e0-8660-46e2fff714d2\"\n}"},"description":"Create a new absence","header":[{"key":"Content-Type","value":"application/json"}],"method":"POST","url":{"host":["{{base_url}}"],"path":["api","v1","absences"],"query":[],"raw":"{{base_url}}/api/v1/absences","variable":[]}}},{"name":"Show an absence","request":{"description":"Show an absence by id or idx","header":[],"method":"GET","url":{"host":["{{base_url}}"],"path":["api","v1","absences",":absence_period_id_or_idx"],"query":[{"description":"When true, each linked/unlinked shift will include a payroll_run_rows array with the raw payroll run row data (start_datetime, end_datetime, duration_in_minutes, entry_type, pay_type, variant). Use this when you need the payroll-authoritative datetimes rather than the scheduled shift times.","disabled":true,"key":"include_payroll_run_rows","value":""}],"raw":"{{base_url}}/api/v1/absences/:absence_period_id_or_idx","variable":[{"description":"The Sona unique identifier or external id of the absence","key":"absence_period_id_or_idx","value":""}]}}},{"name":"Update an absence","request":{"body":{"mode":"raw","options":{"raw":{"language":"json"}},"raw":"{\n  \"create_replacement_shifts\": false,\n  \"ends_at\": \"2019-04-20T15:47:58+00:00\",\n  \"is_open_ended\": false,\n  \"sick_note_provided\": false,\n  \"starts_at\": \"2019-04-19T15:47:58+00:00\"\n}"},"description":"Update an absence","header":[{"key":"Content-Type","value":"application/json"}],"method":"PUT","url":{"host":["{{base_url}}"],"path":["api","v1","absences",":absence_period_id_or_idx"],"query":[],"raw":"{{base_url}}/api/v1/absences/:absence_period_id_or_idx","variable":[{"description":"The Sona unique identifier or external id of the absence","key":"absence_period_id_or_idx","value":""}]}}},{"name":"Delete an absence","request":{"body":{"mode":"raw","options":{"raw":{"language":"json"}},"raw":"{\n  \"delete_associated_shifts\": false\n}"},"description":"Delete an absence","header":[{"key":"Content-Type","value":"application/json"}],"method":"DELETE","url":{"host":["{{base_url}}"],"path":["api","v1","absences",":absence_period_id_or_idx"],"query":[],"raw":"{{base_url}}/api/v1/absences/:absence_period_id_or_idx","variable":[{"description":"The Sona unique identifier or external id of the absence","key":"absence_period_id_or_idx","value":""}]}}},{"name":"Amend an absence period","request":{"body":{"mode":"raw","options":{"raw":{"language":"json"}},"raw":"{\n  \"ends_at\": \"2025-01-13T00:00:00Z\",\n  \"is_open_ended\": false,\n  \"payrolled_shifts_options\": {\n    \"during_absence_period\": {\n      \"action\": \"link\",\n      \"pay_variant\": \"Sickness\"\n    },\n    \"outside_absence_period\": {\n      \"action\": \"unlink\",\n      \"pay_variant\": \"Sickness\"\n    }\n  },\n  \"starts_at\": \"2025-01-12T00:00:00Z\"\n}"},"description":"Amends an absence period","header":[{"key":"Content-Type","value":"application/json"}],"method":"POST","url":{"host":["{{base_url}}"],"path":["api","v1","absences",":absence_period_id_or_idx","amend"],"query":[],"raw":"{{base_url}}/api/v1/absences/:absence_period_id_or_idx/amend","variable":[{"description":"The Sona unique identifier or external id of the absence","key":"absence_period_id_or_idx","value":""}]}}}],"name":"Absences"},{"description":null,"item":[{"name":"Get a list of Absence Subtypes for a given Absence Type","request":{"description":"AbsenceSubtype","header":[],"method":"GET","url":{"host":["{{base_url}}"],"path":["api","v1","absence_types",":absence_type_id","absence_subtypes"],"query":[{"description":"Number of elements per page","disabled":true,"key":"page_size","value":""},{"description":"Number of the page","disabled":true,"key":"page","value":""}],"raw":"{{base_url}}/api/v1/absence_types/:absence_type_id/absence_subtypes","variable":[{"description":"Absence Type ID (UUID)","key":"absence_type_id","value":""}]}}},{"name":"Get an individual Absence Subtype","request":{"description":"Get an individual AbsenceSubtype. See the Absence Subtype listing endpoint for a description of Absence Subtypes","header":[],"method":"GET","url":{"host":["{{base_url}}"],"path":["api","v1","absence_types",":absence_type_id","absence_subtypes",":id"],"query":[],"raw":"{{base_url}}/api/v1/absence_types/:absence_type_id/absence_subtypes/:id","variable":[{"description":"Absence Type ID (UUID)","key":"absence_type_id","value":""},{"description":"Absence Subtype ID (UUID)","key":"id","value":""}]}}}],"name":"AbsenceSubtypes"},{"description":null,"item":[{"name":"Get a list of AbsenceTypes","request":{"description":"AbsenceType","header":[],"method":"GET","url":{"host":["{{base_url}}"],"path":["api","v1","absence_types"],"query":[{"description":"Number of elements per page","disabled":true,"key":"page_size","value":""},{"description":"Number of the page","disabled":true,"key":"page","value":""}],"raw":"{{base_url}}/api/v1/absence_types","variable":[]}}},{"name":"Get an individual absence_type","request":{"description":"Get an individual absence_type. See the absence_type listing endpoint for a description of absence_types","header":[],"method":"GET","url":{"host":["{{base_url}}"],"path":["api","v1","absence_types",":absence_type_id"],"query":[],"raw":"{{base_url}}/api/v1/absence_types/:absence_type_id","variable":[{"description":"Sona unique identifier of the absence_type","key":"absence_type_id","value":""}]}}}],"name":"AbsenceTypes"},{"description":null,"item":[{"name":"Create a new absence year","request":{"body":{"mode":"raw","options":{"raw":{"language":"json"}},"raw":"{\n  \"contract_id\": \"4f5c2a36-8f6e-4a0a-9d8e-2b1c7f3e6a51\",\n  \"start_date\": \"2024-07-23\",\n  \"user_id\": \"550e8400-e29b-41d4-a716-446655440000\"\n}"},"description":"Create a new absence year","header":[{"key":"Content-Type","value":"application/json"}],"method":"POST","url":{"host":["{{base_url}}"],"path":["api","v1","absence_years"],"query":[],"raw":"{{base_url}}/api/v1/absence_years","variable":[]}}}],"name":"AbsenceYears"},{"description":null,"item":[{"name":"Get a list of Agencies","request":{"description":"An agency in Sona is a third party business used to provide staff who can be assigned to shifts. Agencies can be created via the Sona UI or dynamically when using the shifts#assign_to_agency Endpoint. An agency worker is simply a user with a link to an agency, these are returned by the users#index endpoint with their `agency_id` set to the value of an agency. Currently a user can only be associated with one agency.","header":[],"method":"GET","url":{"host":["{{base_url}}"],"path":["api","v1","agencies"],"query":[{"description":"Number of elements per page","disabled":true,"key":"page_size","value":""},{"description":"Number of the page","disabled":true,"key":"page","value":""}],"raw":"{{base_url}}/api/v1/agencies","variable":[]}}},{"name":"Get an individual agency","request":{"description":"Returns information about a single agency. See the agency listing endpoint for a description Agencies.","header":[],"method":"GET","url":{"host":["{{base_url}}"],"path":["api","v1","agencies",":agency_id"],"query":[],"raw":"{{base_url}}/api/v1/agencies/:agency_id","variable":[{"description":"Sona unique identifier of the agency","key":"agency_id","value":""}]}}},{"name":"Gets agencies linked to the organisational unit","request":{"description":"Returns a paginated list of agencies linked to the organisational unit.","header":[],"method":"GET","url":{"host":["{{base_url}}"],"path":["api","v1","org_units",":org_unit_id","agencies"],"query":[],"raw":"{{base_url}}/api/v1/org_units/:org_unit_id/agencies","variable":[{"description":"Sona unique identifier of the organisational unit","key":"org_unit_id","value":""}]}}},{"name":"Links an agency to the organisational unit","request":{"description":"Links an agency to the organisational unit","header":[],"method":"POST","url":{"host":["{{base_url}}"],"path":["api","v1","org_units",":org_unit_id","agencies",":agency_id","link"],"query":[],"raw":"{{base_url}}/api/v1/org_units/:org_unit_id/agencies/:agency_id/link","variable":[{"description":"Sona unique identifier of the organisational unit","key":"org_unit_id","value":""},{"description":"Sona unique identifier of the agency","key":"agency_id","value":""}]}}},{"name":"Unlinks an agency to the organisational unit","request":{"description":"Unlinks an agency to the organisational unit","header":[],"method":"DELETE","url":{"host":["{{base_url}}"],"path":["api","v1","org_units",":org_unit_id","agencies",":agency_id","link"],"query":[],"raw":"{{base_url}}/api/v1/org_units/:org_unit_id/agencies/:agency_id/link","variable":[{"description":"Sona unique identifier of the organisational unit","key":"org_unit_id","value":""},{"description":"Sona unique identifier of the agency","key":"agency_id","value":""}]}}}],"name":"Agencies"},{"description":null,"item":[{"name":"Get a list of annual leave requests","request":{"description":"Returns a list of annual leave requests sorted by creation date. Allows filtering by `user_id` and start and end dates.","header":[],"method":"GET","url":{"host":["{{base_url}}"],"path":["api","v1","annual_leave_requests"],"query":[{"description":"Number of elements per page","disabled":true,"key":"page_size","value":""},{"description":"Number of the page","disabled":true,"key":"page","value":""},{"description":"The user ID to filter by","disabled":true,"key":"user_id","value":""},{"description":"Returns annual leave requests starting on or after the given date","disabled":true,"key":"min_start_date","value":""},{"description":"Returns annual leave requests ending on or before the given date","disabled":true,"key":"max_end_date","value":""},{"description":"The external ID to filter by","disabled":true,"key":"idx","value":""},{"description":"The source type of the external ID to filter by","disabled":true,"key":"source_type","value":""}],"raw":"{{base_url}}/api/v1/annual_leave_requests","variable":[]}}},{"name":"Get an annual leave request by ID","request":{"description":"Returns an annual leave request by ID","header":[],"method":"GET","url":{"host":["{{base_url}}"],"path":["api","v1","annual_leave_requests",":annual_leave_request_id"],"query":[],"raw":"{{base_url}}/api/v1/annual_leave_requests/:annual_leave_request_id","variable":[{"description":"The ID of the annual leave request to get","key":"annual_leave_request_id","value":""}]}}}],"name":"AnnualLeaveRequests"},{"description":null,"item":[{"name":"Get a list of auth strategies for a user","request":{"description":"List all authentication strategies for the given user","header":[],"method":"GET","url":{"host":["{{base_url}}"],"path":["api","v1","users",":users_id","auth_strategies"],"query":[],"raw":"{{base_url}}/api/v1/users/:users_id/auth_strategies","variable":[{"description":"Sona unique identifier of the user","key":"users_id","value":""}]}}},{"name":"Get an individual user auth strategy","request":{"description":"Get an individual authentication strategy for the given user","header":[],"method":"GET","url":{"host":["{{base_url}}"],"path":["api","v1","users",":users_id","auth_strategies",":id"],"query":[],"raw":"{{base_url}}/api/v1/users/:users_id/auth_strategies/:id","variable":[{"description":"Sona unique identifier of the user","key":"users_id","value":""},{"description":"Sona unique identifier of the auth strategy","key":"id","value":""}]}}},{"name":"Update an individual user auth strategy","request":{"body":{"mode":"raw","options":{"raw":{"language":"json"}},"raw":"{\n  \"key\": \"newemail@example.com\"\n}"},"description":"Update an existing authentication strategy for the given user","header":[{"key":"Content-Type","value":"application/json"}],"method":"PUT","url":{"host":["{{base_url}}"],"path":["api","v1","users",":users_id","auth_strategies",":id"],"query":[],"raw":"{{base_url}}/api/v1/users/:users_id/auth_strategies/:id","variable":[{"description":"Sona unique identifier of the user","key":"users_id","value":""},{"description":"Sona unique identifier of the auth strategy","key":"id","value":""}]}}},{"name":"Delete an individual user auth strategy","request":{"description":"Delete an authentication strategy for the given user","header":[],"method":"DELETE","url":{"host":["{{base_url}}"],"path":["api","v1","users",":users_id","auth_strategies",":id"],"query":[],"raw":"{{base_url}}/api/v1/users/:users_id/auth_strategies/:id","variable":[{"description":"Sona unique identifier of the user","key":"users_id","value":""},{"description":"Sona unique identifier of the auth strategy","key":"id","value":""}]}}}],"name":"AuthStrategies"},{"description":null,"item":[{"name":"List care packages","request":{"description":"Newest first. Requires demand-based rostering to be enabled for your organisation (403 otherwise). `updated_at` counts a change to the package (including being superseded) or a new approval status on any of its hour lines.\n","header":[],"method":"GET","url":{"host":["{{base_url}}"],"path":["api","v1","care_packages"],"query":[{"description":"Number of elements per page","disabled":true,"key":"page_size","value":""},{"description":"Number of the page","disabled":true,"key":"page","value":""},{"description":"Only this person's packages (Sona id)","disabled":true,"key":"pws_id","value":""},{"description":"Only this person's packages (their `upload_id`)","disabled":true,"key":"pws_idx","value":""},{"description":"Exact match on the package code","disabled":true,"key":"idx","value":""},{"description":"`true` only packages in force today (started, and not ended; UTC date), `false` only the others: ended, or starting later","disabled":true,"key":"current","value":""},{"description":"Packages starting on or after this date (YYYY-MM-DD)","disabled":true,"key":"start_date_from","value":""},{"description":"Packages starting on or before this date (YYYY-MM-DD)","disabled":true,"key":"start_date_to","value":""},{"description":"Only packages changed on or after this UTC datetime (ISO 8601, trailing Z)","disabled":true,"key":"updated_at","value":""}],"raw":"{{base_url}}/api/v1/care_packages","variable":[]}}},{"name":"Get a care package","request":{"description":"One package with its hour lines. Use the Sona id, or the package code (`idx`) with `is_idx=true`. `status` is the package's overall approval state (`pending`, `pre_approved`, `approved`, `rejected` or `partially_approved`), worked out from the latest status of each hour line. Hour lines are returned in the order they were given, except on packages created before 23 October 2026: that order wasn't recorded, so their lines come back in a fixed order that may differ from it.","header":[],"method":"GET","url":{"host":["{{base_url}}"],"path":["api","v1","care_packages",":care_package_id"],"query":[{"description":"Set to true to look the package up by `idx`","disabled":true,"key":"is_idx","value":""}],"raw":"{{base_url}}/api/v1/care_packages/:care_package_id","variable":[{"description":"Sona id, or `idx` when `is_idx=true`","key":"care_package_id","value":""}]}}},{"name":"List an hour line's approval statuses","request":{"description":"The line's approval history, newest first (by `effective_date`, then when it was added). The first entry is the line's current status. Requires demand-based rostering to be enabled for your organisation (403 otherwise).","header":[],"method":"GET","url":{"host":["{{base_url}}"],"path":["api","v1","care_packages",":care_package_id","hours",":hour_id","statuses"],"query":[{"description":"Number of elements per page","disabled":true,"key":"page_size","value":""},{"description":"Number of the page","disabled":true,"key":"page","value":""},{"description":"Set to true to look the package up by its code (`idx`)","disabled":true,"key":"is_idx","value":""}],"raw":"{{base_url}}/api/v1/care_packages/:care_package_id/hours/:hour_id/statuses","variable":[{"description":"Sona id, or the package code when `is_idx=true`","key":"care_package_id","value":""},{"description":"The hour line's Sona id, from the care package","key":"hour_id","value":""}]}}},{"name":"Add an approval status to an hour line","request":{"body":{"mode":"raw","options":{"raw":{"language":"json"}},"raw":"{\n  \"effective_date\": \"2026-10-12\",\n  \"notes\": \"Signed off by the commissioner\",\n  \"status\": \"approved\"\n}"},"description":"Appends an approval status to one hour line. A status is **added, never edited**, and the latest one is the line's current approval. There is no workflow: any status may follow any other. `effective_date` defaults to today, the UTC date as in the admin panel; it can't be in the future, before the package starts, or before the line's current status (a status is added, never back-dated). A new line starts as `pending`. The package's overall status updates from its lines. Once every line is `rejected` the package is withdrawn, as in the admin panel: it no longer counts towards demand and takes no more statuses (409); create a new package instead.\n","header":[{"key":"Content-Type","value":"application/json"}],"method":"POST","url":{"host":["{{base_url}}"],"path":["api","v1","care_packages",":care_package_id","hours",":hour_id","statuses"],"query":[{"description":"Set to true to look the package up by its code (`idx`)","disabled":true,"key":"is_idx","value":""}],"raw":"{{base_url}}/api/v1/care_packages/:care_package_id/hours/:hour_id/statuses","variable":[{"description":"Sona id, or the package code when `is_idx=true`","key":"care_package_id","value":""},{"description":"The hour line's Sona id, from the care package","key":"hour_id","value":""}]}}},{"name":"Add the same approval status to every hour line of a package","request":{"body":{"mode":"raw","options":{"raw":{"language":"json"}},"raw":"{\n  \"effective_date\": \"2026-10-12\",\n  \"notes\": \"Signed off by the commissioner\",\n  \"status\": \"approved\"\n}"},"description":"Applies one status to **every** hour line of the package in one call, all or nothing. The same date rules apply to each line, so if any line can't take the date, none changes. Returns one entry per line. Rejecting every line withdraws the package, and a withdrawn package takes no more statuses (409).","header":[{"key":"Content-Type","value":"application/json"}],"method":"POST","url":{"host":["{{base_url}}"],"path":["api","v1","care_packages",":care_package_id","statuses"],"query":[{"description":"Set to true to look the package up by its code (`idx`)","disabled":true,"key":"is_idx","value":""}],"raw":"{{base_url}}/api/v1/care_packages/:care_package_id/statuses","variable":[{"description":"Sona id, or the package code when `is_idx=true`","key":"care_package_id","value":""}]}}},{"name":"List a person's care packages","request":{"description":"Newest first. Requires demand-based rostering to be enabled for your organisation (403 otherwise). `updated_at` counts a change to the package (including being superseded) or a new approval status on any of its hour lines.\n","header":[],"method":"GET","url":{"host":["{{base_url}}"],"path":["api","v1","people_we_support",":person_we_support_id","care_packages"],"query":[{"description":"Number of elements per page","disabled":true,"key":"page_size","value":""},{"description":"Number of the page","disabled":true,"key":"page","value":""},{"description":"Set to true to look the person up by `upload_id`","disabled":true,"key":"is_idx","value":""},{"description":"Exact match on the package code","disabled":true,"key":"idx","value":""},{"description":"`true` only packages in force today (started, and not ended; UTC date), `false` only the others: ended, or starting later","disabled":true,"key":"current","value":""},{"description":"Packages starting on or after this date (YYYY-MM-DD)","disabled":true,"key":"start_date_from","value":""},{"description":"Packages starting on or before this date (YYYY-MM-DD)","disabled":true,"key":"start_date_to","value":""},{"description":"Only packages changed on or after this UTC datetime","disabled":true,"key":"updated_at","value":""}],"raw":"{{base_url}}/api/v1/people_we_support/:person_we_support_id/care_packages","variable":[{"description":"Sona id, or `upload_id` when `is_idx=true`","key":"person_we_support_id","value":""}]}}},{"name":"Create a care package","request":{"body":{"mode":"raw","options":{"raw":{"language":"json"}},"raw":"{\n  \"banking_enabled\": false,\n  \"hours\": [\n    {\n      \"assignment_count\": 1,\n      \"demand_period_ids\": [\n        \"7a1f0c9e-2b3d-4c5e-8f60-1a2b3c4d5e6f\"\n      ],\n      \"hours\": 84,\n      \"org_unit_idx\": \"SVC001\",\n      \"staff_count\": 1,\n      \"type_of_work_idx\": \"PERSONAL_CARE\"\n    }\n  ],\n  \"idx\": \"pkg_a_2026\",\n  \"name\": \"Alice 2026\",\n  \"shared_care_during_specified\": true,\n  \"start_date\": \"2026-01-01\"\n}"},"description":"Creates a care package for a person. **Care packages are never edited.** A change is a new package with a later `start_date`, which ends the person's current package the day before and links it. `start_date` must be after the current package's start (no back-dating), and `idx`, your own id for the package, must be unique in your organisation. Everything is referenced by id, never by name: each hour line names its care type (`type_of_work_id` or `type_of_work_idx`), its service (`org_unit_id` or `org_unit_idx`) and at least one `demand_period_ids` entry, and every demand period must belong to that line's service. All or nothing: one invalid line means no package. Every hour line starts as `pending`. Up to 100 hour lines.","header":[{"key":"Content-Type","value":"application/json"}],"method":"POST","url":{"host":["{{base_url}}"],"path":["api","v1","people_we_support",":person_we_support_id","care_packages"],"query":[{"description":"Set to true to look the person up by `upload_id`","disabled":true,"key":"is_idx","value":""}],"raw":"{{base_url}}/api/v1/people_we_support/:person_we_support_id/care_packages","variable":[{"description":"Sona id, or `upload_id` when `is_idx=true`","key":"person_we_support_id","value":""}]}}}],"name":"CarePackages"},{"description":null,"item":[{"name":"Get a list of ContractedHours","request":{"description":"Contracted Hours","header":[],"method":"GET","url":{"host":["{{base_url}}"],"path":["api","v1","contracted_hours"],"query":[{"description":"Number of elements per page","disabled":true,"key":"page_size","value":""},{"description":"Number of the page","disabled":true,"key":"page","value":""},{"description":"The external id to filter by","disabled":true,"key":"idx","value":""},{"description":"The start_date to filter by. Expecting YYYY-MM-DD format.","disabled":true,"key":"start_date","value":""},{"description":"The finish_date to filter by. Expecting YYYY-MM-DD format.","disabled":true,"key":"finish_date","value":""},{"description":"The user_id to filter by","disabled":true,"key":"user_id","value":""},{"description":"The employment_period_id to filter results by","disabled":true,"key":"employment_period_id","value":""}],"raw":"{{base_url}}/api/v1/contracted_hours","variable":[]}}},{"name":"Create new contracted hours","request":{"body":{"mode":"raw","options":{"raw":{"language":"json"}},"raw":"{\n  \"colour_coding\": true,\n  \"days\": 5,\n  \"employment_period_id\": \"159600fb-3fa9-4687-bbc9-196375de6ee3\",\n  \"employment_period_idx\": \"159600fb-3fa9-4687-bbc9-196375de6ee3\",\n  \"finish_date\": \"2024-05-05\",\n  \"hours\": 40.0,\n  \"idx\": \"test_idx\",\n  \"monthly_period_starts_at\": 5,\n  \"org_units\": [\n    {\n      \"id\": \"159600fb-3fa9-4687-bbc9-196375de6ee3\"\n    },\n    {\n      \"id\": \"2a1b3c4d-5e6f-7a8b-9c0d-1e2f3a4b5c6d\"\n    }\n  ],\n  \"period\": \"weekly\",\n  \"rolling_period_sequence_length_days\": 20,\n  \"rolling_period_sequence_start\": \"2024-03-01\",\n  \"start_date\": \"2024-01-01\",\n  \"types_of_work\": [\n    {\n      \"id\": \"159600fb-3fa9-4687-bbc9-196375de6ee3\"\n    }\n  ],\n  \"weekly_period_starts_at\": \"tuesday\"\n}"},"description":"Create new contracted hours. See the ContractedHours listing endpoint for a description of a contracted hours. One of the employment_period_id or employment_period_idx parameters is required. The hours are bounded by the length of the period: at most 168 for `weekly`, 744 for `monthly` and `calendar_month_daily`, and 24 per day of `rolling_period_sequence_length_days` for `rolling_sequence`. Hours beyond that are rejected with a 422, on create and on any update that names `hours`, `period` or `rolling_period_sequence_length_days`. Contracted hours can't overlap other contracted hours on the same employment spec with the same `period` (for `rolling_sequence`, the same length) and the same or intersecting types of work and org units; an overlap is rejected with a 422 under `duplicate`. Creating open-ended hours (no `finish_date`) that start after open-ended hours of the same kind ends those hours the day before instead. Where the only overlap is the day one record ends and the next of the same kind starts, the earlier record is ended the day before instead.","header":[{"key":"Content-Type","value":"application/json"}],"method":"POST","url":{"host":["{{base_url}}"],"path":["api","v1","contracted_hours"],"query":[],"raw":"{{base_url}}/api/v1/contracted_hours","variable":[]}}},{"name":"Get individual contracted_hours","request":{"description":"Get individual contracted_hours. See the contracted_hours listing endpoint for a description of contracted_hours","header":[],"method":"GET","url":{"host":["{{base_url}}"],"path":["api","v1","contracted_hours",":contracted_hours_id_or_idx"],"query":[{"description":"IF contracted_hours_id_or_idx is an external id, this parameter should be set to true","disabled":true,"key":"is_idx","value":""},{"description":"The date from when these contracted hours are applicable","disabled":true,"key":"start_date","value":""},{"description":"The date from when these contracted hours are no longer applicable","disabled":true,"key":"finish_date","value":""},{"description":"Sona unique identifier of the type of work condition to filter contracted hours by","disabled":true,"key":"type_of_work_id","value":""},{"description":"Sona unique identifier of the location condition to filter contracted hours by","disabled":true,"key":"org_unit_id","value":""}],"raw":"{{base_url}}/api/v1/contracted_hours/:contracted_hours_id_or_idx","variable":[{"description":"Sona unique identifier or external id of the contracted hours","key":"contracted_hours_id_or_idx","value":""}]}}},{"name":"Update an existing contracted hours","request":{"body":{"mode":"raw","options":{"raw":{"language":"json"}},"raw":"{\n  \"age\": 3,\n  \"name\": \"Updated value\"\n}"},"description":"Update an existing contracted hours. See the ContractedHours listing endpoint for a description of a contracted hours.  One of the id or idx parameters is required. If both employment_period_id and employment_period_idx are given employment_period_id has a higher precedence. The hours are bounded by the length of the period: at most 168 for `weekly`, 744 for `monthly` and `calendar_month_daily`, and 24 per day of `rolling_period_sequence_length_days` for `rolling_sequence`. Hours beyond that are rejected with a 422, on create and on any update that names `hours`, `period` or `rolling_period_sequence_length_days`. An update is rejected with a 422 under `duplicate` if it makes these hours overlap other contracted hours on the same employment spec with the same `period` (for `rolling_sequence`, the same length) and the same or intersecting types of work and org units. Where the only overlap is the day one record ends and the next of the same kind starts, the earlier record is ended the day before instead.","header":[{"key":"Content-Type","value":"application/json"}],"method":"PUT","url":{"host":["{{base_url}}"],"path":["api","v1","contracted_hours",":contracted_hours_id_or_idx"],"query":[],"raw":"{{base_url}}/api/v1/contracted_hours/:contracted_hours_id_or_idx","variable":[{"description":"Sona unique identifier or external id of the contracted hours","key":"contracted_hours_id_or_idx","value":""}]}}},{"name":"Delete contracted hours","request":{"description":"Delete a future dated contracted hours record. Contracted hours that start today or earlier, in your organisation's timezone, cannot be deleted. When addressing the record by external id, start_date and type_of_work_id are required alongside is_idx. A token restricted to specific endpoints needs `DELETE /api/v1/contracted_hours/:id` in its list, or the response is a 403.","header":[],"method":"DELETE","url":{"host":["{{base_url}}"],"path":["api","v1","contracted_hours",":contracted_hours_id_or_idx"],"query":[{"description":"IF contracted_hours_id_or_idx is an external id, this parameter should be set to true","disabled":true,"key":"is_idx","value":""},{"description":"The date from when these contracted hours are applicable","disabled":true,"key":"start_date","value":""},{"description":"Sona unique identifier of the type of work condition to filter contracted hours by","disabled":true,"key":"type_of_work_id","value":""}],"raw":"{{base_url}}/api/v1/contracted_hours/:contracted_hours_id_or_idx","variable":[{"description":"Sona unique identifier or external id of the contracted hours","key":"contracted_hours_id_or_idx","value":""}]}}}],"name":"ContractedHours"},{"description":null,"item":[{"name":"Get a list of Contract Types","request":{"description":"Contract type","header":[],"method":"GET","url":{"host":["{{base_url}}"],"path":["api","v1","contract_types"],"query":[{"description":"Number of elements per page","disabled":true,"key":"page_size","value":""},{"description":"Number of the page","disabled":true,"key":"page","value":""}],"raw":"{{base_url}}/api/v1/contract_types","variable":[]}}},{"name":"Get an individual contract type","request":{"description":"Get an individual contract type. See the contract type listing endpoint for a description of contract types","header":[],"method":"GET","url":{"host":["{{base_url}}"],"path":["api","v1","contract_types",":contract_type_id"],"query":[],"raw":"{{base_url}}/api/v1/contract_types/:contract_type_id","variable":[{"description":"Sona unique identifier of the contract_type","key":"contract_type_id","value":""}]}}}],"name":"ContractTypes"},{"description":null,"item":[{"name":"Upload a CSV file to the importer","request":{"body":{"formdata":[{"description":"CSV file","key":"csv","type":"file","value":""}],"mode":"formdata"},"description":"Uploads a CSV file to the importer, and returns a report of running the import","header":[],"method":"POST","url":{"host":["{{base_url}}"],"path":["api","v1","csv_imports","upload",":file_type"],"query":[],"raw":"{{base_url}}/api/v1/csv_imports/upload/:file_type","variable":[{"description":"CSV file type","key":"file_type","value":""}]}}}],"name":"CsvImports"},{"description":null,"item":[{"name":"Get a list of CustomFormEntries","request":{"description":"Custom Form Entries","header":[],"method":"GET","url":{"host":["{{base_url}}"],"path":["api","v1","custom_form_entries"],"query":[{"description":"Number of elements per page","disabled":true,"key":"page_size","value":""},{"description":"Number of the page","disabled":true,"key":"page","value":""}],"raw":"{{base_url}}/api/v1/custom_form_entries","variable":[]}}},{"name":"Create new custom form entry","request":{"body":{"mode":"raw","options":{"raw":{"language":"json"}},"raw":"{\n  \"custom_form_id\": \"159600fb-3fa9-4687-bbc9-196375de6ee3\",\n  \"employee_document_type\": \"CV\",\n  \"user_id\": \"74a1af00-d181-4c95-bb6a-aab800185595\"\n}"},"description":"Create a new custom form entry.\n\n**Step-by-step workflow:**\n\n1. **Fetch the custom form** — call `GET /api/v1/custom_forms/{custom_form_id}` to retrieve the form definition.\n2. **Check `submission_type`** — this determines which fields are required:\n   - `single` — send `custom_form_id`, `user_id`, and every field from the form's single fieldset.\n   - `multiple` — the form has several fieldsets, one per document type. Pick the document type you need, then send `custom_form_id`, `user_id`, `employee_document_type`, and every field from the matching fieldset.\n3. **Find the field keys** — look at the `schema.fieldsets[].fields[].name` values in the custom form response. These are the keys to include in your create request.\n4. **For `multiple` forms, find valid document types** — each fieldset (after the first) has a `variation.value` (e.g. `\"CV\"`, `\"Passport\"`). Pass the chosen value as `employee_document_type`.\n\n**Important — field names must be exact:** any parameter that does not match a field `name` from the custom form's schema is silently ignored. If your file upload or other fields appear as `null` in the response `data` object, check that the parameter names in your request exactly match the field names from `GET /api/v1/custom_forms/{id}`. There is no `file`, `document`, or `type` parameter — the file content must be the value of the field's own name (e.g. `document_1`).\n\n**File uploads** can be sent in three ways:\n\n1. `multipart/form-data` with a `Plug.Upload` file field (standard browser-style upload)\n2. `application/json` with a data URL string: `\"data:application/pdf;base64,JVBERi0xLjQ...\"`\n3. `application/json` with a JSON object: `{\"base64\": \"JVBERi0xLjQ...\", \"filename\": \"doc.pdf\", \"content_type\": \"application/pdf\"}`\n   - `base64` is required\n   - At least one of `filename` or `content_type` must be provided\n   - If `content_type` is omitted it is inferred from the filename extension\n\n**Base64 upload limits:**\n- Maximum file size: 30 MB (after decoding)\n- Allowed content types: PDF, PNG, JPEG, GIF, WebP, SVG, Word, Excel, PowerPoint, plain text, CSV, RTF\n- Maximum JSON request body: 60 MB by default (all fields combined, after base64 encoding)\n- Note: a 30 MB file is ~40 MB when base64-encoded. For large files, prefer multipart uploads.\n","header":[{"key":"Content-Type","value":"application/json"}],"method":"POST","url":{"host":["{{base_url}}"],"path":["api","v1","custom_form_entries"],"query":[],"raw":"{{base_url}}/api/v1/custom_form_entries","variable":[]}}},{"name":"Get individual custom_form_entries","request":{"description":"Get an individual custom_form_entry. See the custom_form_entries listing endpoint for a description of custom_form_entries","header":[],"method":"GET","url":{"host":["{{base_url}}"],"path":["api","v1","custom_form_entries",":custom_form_entry_id"],"query":[],"raw":"{{base_url}}/api/v1/custom_form_entries/:custom_form_entry_id","variable":[{"description":"Sona unique identifier of the custom_form_entry","key":"custom_form_entry_id","value":""}]}}},{"name":"Update an existing custom form entry","request":{"body":{"mode":"raw","options":{"raw":{"language":"json"}},"raw":"{\n  \"age\": 3,\n  \"name\": \"Updated value\"\n}"},"description":"Update an existing custom form entry. Only the fields provided in the request body\nwill be updated; omitted fields retain their current values.\n\nThe `custom_form_id` and `user_id` cannot be changed after creation.\n\n**⚠ Important — updating entries can affect other parts of the system:**\n\nCustom form entries may be referenced by other Sona subsystems. Updating field values\ncan have downstream consequences including:\n\n- **Payroll** — If the entry has been used to generate payroll additional payment/deduction\n  elements, updating field values will **not** retroactively update those payroll records.\n  This can cause discrepancies between the entry data and what was submitted to payroll.\n- **Approval workflows** — Entries linked to an approval (pending or completed) cannot be\n  updated. The request will return a `422` error.\n- **Shifts** — Entries linked to shifts (e.g. shift-specific custom form data) will reflect\n  the updated values. Ensure the new values are still valid in the context of the shift.\n- **Employee documents** — If the entry is linked to employee document versions, updating\n  file upload fields may leave stale references to previous document versions.\n- **Form requests** — Entries created via form requests (e.g. self-service or manager\n  submissions) are linked back to the form request record. Updating the entry directly\n  bypasses any form request validation or approval logic.\n- **Data gathering steps** — If the entry was created as part of a data gathering workflow,\n  updating it directly bypasses the step completion logic and may cause the step to appear\n  out of sync with its stored data.\n- **Workflows** — Entries produced by automated workflows are tracked as workflow outputs.\n  Updating these entries does not re-trigger or update the workflow.\n- **HR reports** — Reports that reference custom form entry data will reflect updated values\n  on next run, which may change historical report outputs.\n\nAlways verify whether the entry is connected to other processes before updating via the API.\n","header":[{"key":"Content-Type","value":"application/json"}],"method":"PUT","url":{"host":["{{base_url}}"],"path":["api","v1","custom_form_entries",":id"],"query":[],"raw":"{{base_url}}/api/v1/custom_form_entries/:id","variable":[{"description":"Sona unique identifier of the custom form entry","key":"id","value":""}]}}},{"name":"Delete a custom form entry","request":{"description":"Permanently delete a custom form entry. **This action cannot be undone.**\n\n**⚠ Important — deleting entries has cascading effects across the system:**\n\nCustom form entries are referenced by multiple Sona subsystems. Deleting an entry\nwill have the following consequences:\n\n- **Tasks** — Any incomplete tasks linked to this entry will be **automatically marked\n  as completed**. This is irreversible and may confuse users who see tasks disappear\n  from their task list without explanation.\n- **Payroll** — Entries that have been submitted to payroll (i.e. have linked payroll\n  additional payment/deduction elements) **cannot be deleted**. The request will return\n  a `422` error. This is enforced by a database constraint to prevent orphaned payroll\n  records.\n- **Approval workflows** — Entries linked to any approval record (pending, approved, or\n  rejected) **cannot be deleted**. The request will return a `422` error.\n- **Locked entries** — Entries that have been locked (e.g. by an approval or payroll\n  workflow) **cannot be deleted**. The request will return a `422` error.\n- **Shifts** — If the entry is linked to a shift via the shifts–custom-form-entries\n  association, deletion will leave the shift with a broken reference. The shift may no\n  longer display its associated custom form data correctly.\n- **Employee documents** — If the entry is linked to employee document versions, deletion\n  may orphan the document version records, causing missing data in the employee's\n  document history.\n- **Form requests** — If the entry was created via a form request (self-service or manager\n  submission), the form request record will retain a reference to the now-deleted entry,\n  which may cause errors when viewing the form request history.\n- **Data gathering steps** — If the entry was created as part of a data gathering workflow,\n  deletion will leave the step referencing a non-existent entry, potentially breaking the\n  data gathering flow.\n- **Workflows** — If the entry was produced by an automated workflow, the workflow output\n  record will retain a dangling reference. Re-running the workflow will not recreate the\n  deleted entry.\n- **HR reports** — Reports referencing the deleted entry's data will no longer include it,\n  which may change historical report outputs.\n\nAlways verify whether the entry is connected to other processes before deleting via the API.\nUse `GET /api/v1/custom_form_entries/{id}` to inspect the entry first.\n","header":[],"method":"DELETE","url":{"host":["{{base_url}}"],"path":["api","v1","custom_form_entries",":id"],"query":[],"raw":"{{base_url}}/api/v1/custom_form_entries/:id","variable":[{"description":"Sona unique identifier of the custom form entry","key":"id","value":""}]}}}],"name":"CustomFormEntries"},{"description":null,"item":[{"name":"Get a list of CustomForms","request":{"description":"Custom Forms","header":[],"method":"GET","url":{"host":["{{base_url}}"],"path":["api","v1","custom_forms"],"query":[{"description":"Number of elements per page","disabled":true,"key":"page_size","value":""},{"description":"Number of the page","disabled":true,"key":"page","value":""}],"raw":"{{base_url}}/api/v1/custom_forms","variable":[]}}},{"name":"Get individual custom_form","request":{"description":"Get individual custom_form. See the custom_forms listing endpoint for a description of custom_forms","header":[],"method":"GET","url":{"host":["{{base_url}}"],"path":["api","v1","custom_forms",":custom_form_id"],"query":[],"raw":"{{base_url}}/api/v1/custom_forms/:custom_form_id","variable":[{"description":"Sona unique identifier","key":"custom_form_id","value":""}]}}}],"name":"CustomForms"},{"description":null,"item":[{"name":"List of Employment Periods","request":{"description":"Returns a paginated list of employment periods. Supports filtering by employee number, external identifier, user ID, or last updated timestamp.\n\n**Pagination**: Results are paginated. Use the `page` and `page_size` query parameters to navigate. The default page size is 10. Note: the parameter name is `page` (not `page_number`). The response includes `page_number`, `page_size`, `total_pages`, and `total_entries` metadata to assist with iteration. Example: `GET /api/v1/employment_periods?page=2&page_size=100`","header":[],"method":"GET","url":{"host":["{{base_url}}"],"path":["api","v1","employment_periods"],"query":[{"description":"Number of elements per page","disabled":true,"key":"page_size","value":""},{"description":"Number of the page","disabled":true,"key":"page","value":""},{"description":"Unique number of the employee who is working this employment_period","disabled":true,"key":"employee_number","value":""},{"description":"The idx (external identifier) to filter by","disabled":true,"key":"idx","value":""},{"description":"The user_id to filter by","disabled":true,"key":"user_id","value":""},{"description":"UTC datetime to filter employment periods updated on or after this timestamp. Use format YYYY-MM-DDThh:mm:ssZ in UTC (e.g. 2024-01-15T10:00:00Z)","disabled":true,"key":"updated_at","value":""}],"raw":"{{base_url}}/api/v1/employment_periods","variable":[]}}},{"name":"Create a new employment_period","request":{"body":{"mode":"raw","options":{"raw":{"language":"json"}},"raw":"{\n  \"active\": true,\n  \"continuous_employment_start_date\": \"2019-07-20\",\n  \"employee_number\": \"A568675\",\n  \"employment_specs\": [\n    {\n      \"contract_types\": [\n        {\n          \"id\": \"159600fb-3fa9-4687-bbc9-196375de6ee3\"\n        }\n      ],\n      \"contracted_hours\": [\n        {\n          \"days\": 10,\n          \"finish_date\": \"2020-04-20\",\n          \"hours\": 30.0,\n          \"idx\": \"external id\",\n          \"monthly_period_starts_at\": 1,\n          \"org_unit_id\": \"159600fb-3fa9-4687-bbc9-196375de6ee3\",\n          \"period\": \"weekly\",\n          \"rolling_period_sequence_length_days\": 20,\n          \"rolling_period_sequence_start\": \"2024-03-01\",\n          \"start_date\": \"2019-04-20\",\n          \"type_of_work_id\": \"159600fb-3fa9-4687-bbc9-196375de6ee3\",\n          \"weekly_period_starts_at\": \"tuesday\"\n        }\n      ],\n      \"rates_of_pay\": [\n        {\n          \"id\": \"159600fb-3fa9-4687-bbc9-196375de6ee3\"\n        },\n        {\n          \"amount\": 1000,\n          \"currency\": \"GBP\",\n          \"finish_date\": \"2025-04-20\",\n          \"idx\": \"external id\",\n          \"is_default\": true,\n          \"pay_type\": \"salaried\",\n          \"start_date\": \"2019-04-20\"\n        }\n      ]\n    }\n  ],\n  \"finish_date\": \"2020-04-20\",\n  \"forces_new_holiday_breakdown\": false,\n  \"idx\": \"external idx\",\n  \"job_grade_id\": \"159600fb-3fa9-4687-bbc9-196375de6ee3\",\n  \"job_id\": \"159600fb-3fa9-4687-bbc9-196375de6ee3\",\n  \"level_id\": \"159600fb-3fa9-4687-bbc9-196375de6ee3\",\n  \"permission_roles\": [\n    {\n      \"id\": \"84f0d476-f2d6-43c4-adbf-b7f952b0af5f\"\n    },\n    {\n      \"id\": \"18c32388-0a1e-442a-9a2f-3e0621cc068a\"\n    }\n  ],\n  \"primary_org_unit_id\": \"159600fb-3fa9-4687-bbc9-196375de6ee3\",\n  \"probation_end_date\": \"2019-07-20\",\n  \"reports_to_user_id\": \"a1b2c3d4-e5f6-7890-abcd-ef1234567890\",\n  \"start_date\": \"2019-04-20\",\n  \"starter_declaration\": \"A\",\n  \"student_loan_plan_five\": false,\n  \"student_loan_plan_four\": false,\n  \"student_loan_plan_one\": true,\n  \"student_loan_plan_two\": false,\n  \"student_loan_post_graduate\": false,\n  \"tupe\": false,\n  \"types_of_work\": [\n    {\n      \"id\": \"3214f01b-7264-4c79-846a-8583a75e1d70\"\n    },\n    {\n      \"id\": \"15bb52f6-7f37-4ac8-84ee-71fbca32106d\"\n    }\n  ],\n  \"user_id\": \"7fe0866b-9631-42cb-94b1-d8e426ac0fb0\"\n}"},"description":"Create a new employment period for a user.\n\n## Employment Specs\n\nAt least one employment spec must be provided, each containing `contract_types`, `rates_of_pay`, and `contracted_hours`.\n\n## Rates of Pay\n\nRates of pay within an employment spec support two modes:\n\n1. **Reference an existing rate**: provide `{\"id\": \"<uuid>\"}` to link a pre-existing rate of pay to the employment spec.\n2. **Create a new rate inline**: omit `id` and provide `amount`, `currency`, `start_date`, `pay_type` (and optionally `finish_date`, `idx`, `is_default`, `label`, `type_of_work_id`, `org_unit_id`) to create a new rate of pay as part of the employment period creation.\n\nBoth modes can be mixed in the same request. When both `id` and inline fields are provided, `id` takes precedence and the inline fields are silently ignored.\n\nWhen creating rates inline, set `is_default` to `true` if the rate should be treated as the default rate for holiday pay derivation (requires the default rates feature to be enabled).\n\nFor organisations with UK minimum wage validation enabled, an inline GBP rate below the apprentice-rate hard floor (£7.55, £8.00 from April 2026) is rejected with a 422 naming the required amount, and no employment period is created. This floor is not age-banded, so a rate that is legal for an apprentice but below the National Living Wage for the employee's age is still accepted. A salaried rate is judged on its hourly equivalent, derived from the `contracted_hours` in the same request. A currency that is not a recognised three-letter ISO 4217 code is also rejected with a 422.\n\nContracted hours are bounded by the length of the period: at most 168 hours for `weekly`, 744 for `monthly` and `calendar_month_daily`, and 24 per day of `rolling_period_sequence_length_days` for `rolling_sequence`. Hours beyond that are rejected with a 422, and no employment period is created.\n\n## Contract\n\nEvery employment period belongs to a contract, identified by `contract_id`.\n\n**Organisations without the overlapping employment periods feature** manage contracts automatically: the new period joins the person's existing contract (inherited from their latest employment period), or starts a new contract if it is their first period. Neither `contract_id` nor `starts_new_contract` may be passed.\n\n**Organisations with the feature enabled** must state the request's intent, one of:\n\n- `contract_id` (with `starts_new_contract` false or omitted): the new period continues that contract. The value must be the `contract_id` of one of the same person's existing employment periods.\n- `starts_new_contract: true`: the new period starts a new contract with an auto-generated `contract_id` — which must therefore not be passed.\n\nThe contract is fixed at creation and cannot be changed via the update endpoint.\n\nTwo more rules apply to organisations with the feature enabled:\n\n- Employment periods on different contracts whose dates overlap must share one `employee_number`. A different number is rejected with a 422 on `employee_number`. An employment period without an employee number neither constrains nor is constrained.\n- To continue a contract, first set a `finish_date` on that contract's current employment period with `PUT /api/v1/employment_periods/{employment_period_id}`, then create the new period with that `contract_id`. While the current employment period has no `finish_date`, a later one is rejected with a 422 on `employee_number`: \"Please, close the latest existing employment period before creating a new one.\" Another contract that is still running does not block it.\n\nTo end one contract while the others continue, set a `finish_date` on its current employment period. `PUT /api/v1/users/{user_id_or_idx}/terminate` ends every contract.\n","header":[{"key":"Content-Type","value":"application/json"}],"method":"POST","url":{"host":["{{base_url}}"],"path":["api","v1","employment_periods"],"query":[],"raw":"{{base_url}}/api/v1/employment_periods","variable":[]}}},{"name":"Delete an employment period","request":{"description":"Delete a future dated employment period. Currently applying employment periods cannot be deleted.","header":[],"method":"DELETE","url":{"host":["{{base_url}}"],"path":["api","v1","employment_periods",":employment_period_id_or_idx"],"query":[],"raw":"{{base_url}}/api/v1/employment_periods/:employment_period_id_or_idx","variable":[{"description":"Sona unique identifier of the employment period or external id","key":"employment_period_id_or_idx","value":""}]}}},{"name":"Update an individual employment_period","request":{"body":{"mode":"raw","options":{"raw":{"language":"json"}},"raw":"{\n  \"active\": true,\n  \"continuous_employment_start_date\": \"2019-07-20\",\n  \"employee_number\": \"A568675\",\n  \"employment_specs\": [\n    {\n      \"contract_types\": [\n        {\n          \"id\": \"159600fb-3fa9-4687-bbc9-196375de6ee3\"\n        }\n      ],\n      \"contracted_hours\": [\n        {\n          \"days\": 10,\n          \"finish_date\": \"2020-04-20\",\n          \"hours\": 30.0,\n          \"idx\": \"external id\",\n          \"monthly_period_starts_at\": 1,\n          \"org_unit_id\": \"159600fb-3fa9-4687-bbc9-196375de6ee3\",\n          \"period\": \"weekly\",\n          \"rolling_period_sequence_length_days\": 20,\n          \"rolling_period_sequence_start\": \"2024-03-01\",\n          \"start_date\": \"2019-04-20\",\n          \"type_of_work_id\": \"159600fb-3fa9-4687-bbc9-196375de6ee3\",\n          \"weekly_period_starts_at\": \"tuesday\"\n        }\n      ],\n      \"rates_of_pay\": [\n        {\n          \"id\": \"159600fb-3fa9-4687-bbc9-196375de6ee3\"\n        },\n        {\n          \"amount\": 1000,\n          \"currency\": \"GBP\",\n          \"finish_date\": \"2025-04-20\",\n          \"idx\": \"external id\",\n          \"is_default\": true,\n          \"pay_type\": \"salaried\",\n          \"start_date\": \"2019-04-20\"\n        }\n      ]\n    }\n  ],\n  \"finish_date\": \"2020-04-20\",\n  \"forces_new_holiday_breakdown\": false,\n  \"idx\": \"external idx\",\n  \"job_grade_id\": \"159600fb-3fa9-4687-bbc9-196375de6ee3\",\n  \"job_id\": \"159600fb-3fa9-4687-bbc9-196375de6ee3\",\n  \"level_id\": \"159600fb-3fa9-4687-bbc9-196375de6ee3\",\n  \"permission_roles\": [\n    {\n      \"id\": \"84f0d476-f2d6-43c4-adbf-b7f952b0af5f\"\n    },\n    {\n      \"id\": \"18c32388-0a1e-442a-9a2f-3e0621cc068a\"\n    }\n  ],\n  \"primary_org_unit_id\": \"159600fb-3fa9-4687-bbc9-196375de6ee3\",\n  \"probation_end_date\": \"2019-07-20\",\n  \"reports_to_user_id\": \"a1b2c3d4-e5f6-7890-abcd-ef1234567890\",\n  \"start_date\": \"2019-04-20\",\n  \"starter_declaration\": \"A\",\n  \"student_loan_plan_five\": false,\n  \"student_loan_plan_four\": false,\n  \"student_loan_plan_one\": true,\n  \"student_loan_plan_two\": false,\n  \"student_loan_post_graduate\": false,\n  \"tupe\": false,\n  \"types_of_work\": [\n    {\n      \"id\": \"3214f01b-7264-4c79-846a-8583a75e1d70\"\n    },\n    {\n      \"id\": \"15bb52f6-7f37-4ac8-84ee-71fbca32106d\"\n    }\n  ],\n  \"user_id\": \"7fe0866b-9631-42cb-94b1-d8e426ac0fb0\"\n}"},"description":"Update an individual employment period based on employment_period_id OR the external idx.\n\n## Rates of Pay\n\nRates of pay within an employment spec support two modes:\n\n1. **Reference an existing rate**: provide `{\"id\": \"<uuid>\"}` to link a pre-existing rate of pay to the employment spec.\n2. **Create a new rate inline**: omit `id` and provide `amount`, `currency`, `start_date`, `pay_type` (and optionally `finish_date`, `idx`, `is_default`, `label`, `type_of_work_id`, `org_unit_id`) to create a new rate of pay as part of the employment period update.\n\nBoth modes can be mixed in the same request. When both `id` and inline fields are provided, `id` takes precedence and the inline fields are silently ignored.\n\nWhen creating rates inline, set `is_default` to `true` if the rate should be treated as the default rate for holiday pay derivation (requires the default rates feature to be enabled).\n","header":[{"key":"Content-Type","value":"application/json"}],"method":"PUT","url":{"host":["{{base_url}}"],"path":["api","v1","employment_periods",":employment_period_id"],"query":[{"description":"External identifier of the employment_period","disabled":true,"key":"idx","value":""}],"raw":"{{base_url}}/api/v1/employment_periods/:employment_period_id","variable":[{"description":"Sona unique identifier of the employment_period","key":"employment_period_id","value":""}]}}}],"name":"EmploymentPeriods"},{"description":null,"item":[{"name":"Bulk update employment spec contract types","request":{"body":{"mode":"raw","options":{"raw":{"language":"json"}},"raw":"[\n  {\n    \"new_contract_type_id\": \"e27ad021-af0e-4ccf-95e8-1c7c84656c93\",\n    \"spec_id\": \"159600fb-3fa9-4687-bbc9-196375de6ee3\"\n  }\n]"},"description":"Update contract types for multiple employment specs.","header":[{"key":"Content-Type","value":"application/json"}],"method":"POST","url":{"host":["{{base_url}}"],"path":["api","v1","employment_specs","contract_type","bulk"],"query":[],"raw":"{{base_url}}/api/v1/employment_specs/contract_type/bulk","variable":[]}}},{"name":"Update an employment spec contract type","request":{"body":{"mode":"raw","options":{"raw":{"language":"json"}},"raw":"{\n  \"contract_type_id\": \"e27ad021-af0e-4ccf-95e8-1c7c84656c93\"\n}"},"description":"Update the contract type for an employment spec.","header":[{"key":"Content-Type","value":"application/json"}],"method":"PUT","url":{"host":["{{base_url}}"],"path":["api","v1","employment_specs",":employment_spec_id","contract_type"],"query":[],"raw":"{{base_url}}/api/v1/employment_specs/:employment_spec_id/contract_type","variable":[{"description":"Sona unique identifier of the employment_spec","key":"employment_spec_id","value":""}]}}}],"name":"EmploymentSpecs"},{"description":null,"item":[{"name":"Get a list of external mappings","request":{"description":"List external mappings for the current organisation","header":[],"method":"GET","url":{"host":["{{base_url}}"],"path":["api","v1","external_mappings"],"query":[{"description":"Number of elements per page","disabled":true,"key":"page_size","value":""},{"description":"Number of the page","disabled":true,"key":"page","value":""},{"description":"Filter by external identifier","disabled":true,"key":"idx","value":""},{"description":"Filter by source type","disabled":true,"key":"source_type","value":""}],"raw":"{{base_url}}/api/v1/external_mappings","variable":[]}}},{"name":"Create a new external mapping","request":{"body":{"mode":"raw","options":{"raw":{"language":"json"}},"raw":"{\n  \"idx\": \"external_id_of_variable_type\",\n  \"source_type\": \"general\",\n  \"user_id\": \"bb000313-0497-443c-b05d-7c68a4f9e812\"\n}"},"description":"Create a new external mapping","header":[{"key":"Content-Type","value":"application/json"}],"method":"POST","url":{"host":["{{base_url}}"],"path":["api","v1","external_mappings"],"query":[],"raw":"{{base_url}}/api/v1/external_mappings","variable":[]}}},{"name":"Get a single external mapping","request":{"description":"Get a single external mapping data.","header":[],"method":"GET","url":{"host":["{{base_url}}"],"path":["api","v1","external_mappings",":id"],"query":[],"raw":"{{base_url}}/api/v1/external_mappings/:id","variable":[{"description":"The Sona unique identifier of the external mapping.","key":"id","value":""}]}}},{"name":"Update an external mapping","request":{"body":{"mode":"raw","options":{"raw":{"language":"json"}},"raw":"{\n  \"idx\": \"external_id_of_variable_type\",\n  \"source_type\": \"general\"\n}"},"description":"Update an external mapping","header":[{"key":"Content-Type","value":"application/json"}],"method":"PUT","url":{"host":["{{base_url}}"],"path":["api","v1","external_mappings",":id"],"query":[],"raw":"{{base_url}}/api/v1/external_mappings/:id","variable":[{"description":"Sona unique identifier of external mapping","key":"id","value":""}]}}}],"name":"ExternalMappings"},{"description":null,"item":[{"name":"Gets the organisational unit features","request":{"description":"Returns the features of the organisational unit.","header":[],"method":"GET","url":{"host":["{{base_url}}"],"path":["api","v1","org_units",":org_unit_id","features"],"query":[],"raw":"{{base_url}}/api/v1/org_units/:org_unit_id/features","variable":[{"description":"Sona unique identifier of the organisational unit","key":"org_unit_id","value":""}]}}},{"name":"Creates new organisational unit features","request":{"body":{"mode":"raw","options":{"raw":{"language":"json"}},"raw":"{\n  \"linked_shift_attendance_required\": false,\n  \"shift_runs_enabled\": false\n}"},"description":"Creates the features for the organisational unit.","header":[{"key":"Content-Type","value":"application/json"}],"method":"POST","url":{"host":["{{base_url}}"],"path":["api","v1","org_units",":org_unit_id","features"],"query":[],"raw":"{{base_url}}/api/v1/org_units/:org_unit_id/features","variable":[{"description":"Sona unique identifier of the organisational unit","key":"org_unit_id","value":""}]}}},{"name":"Updates the organisational unit features","request":{"body":{"mode":"raw","options":{"raw":{"language":"json"}},"raw":"{\n  \"linked_shift_attendance_required\": false,\n  \"shift_runs_enabled\": false\n}"},"description":"Updates the features for the organisational unit.","header":[{"key":"Content-Type","value":"application/json"}],"method":"PUT","url":{"host":["{{base_url}}"],"path":["api","v1","org_units",":org_unit_id","features"],"query":[],"raw":"{{base_url}}/api/v1/org_units/:org_unit_id/features","variable":[{"description":"Sona unique identifier of the organisational unit","key":"org_unit_id","value":""}]}}},{"name":"Deletes the organisational unit features","request":{"description":"Deletes the features for the organisational unit. Succeeds with 204 even if the organisational unit has no features or does not exist, so it is safe to repeat.","header":[],"method":"DELETE","url":{"host":["{{base_url}}"],"path":["api","v1","org_units",":org_unit_id","features"],"query":[],"raw":"{{base_url}}/api/v1/org_units/:org_unit_id/features","variable":[{"description":"Sona unique identifier of the organisational unit","key":"org_unit_id","value":""}]}}}],"name":"FeatureSet"},{"description":null,"item":[{"name":"Record the start of a forecast run","request":{"body":{"mode":"raw","options":{"raw":{"language":"json"}},"raw":"{\n  \"started_at\": \"2026-04-27T09:00:00Z\",\n  \"target\": \"revenue\"\n}"},"description":"Records that a forecast run has started for the authenticated organisation. Returns the forecast run id which the caller must pass back to a terminal endpoint.","header":[{"key":"Content-Type","value":"application/json"}],"method":"POST","url":{"host":["{{base_url}}"],"path":["api","v1","forecast_runs"],"query":[],"raw":"{{base_url}}/api/v1/forecast_runs","variable":[]}}},{"name":"Record the completion of a forecast run","request":{"body":{"mode":"raw","options":{"raw":{"language":"json"}},"raw":"{\n  \"ended_at\": \"2026-04-27T09:14:32Z\",\n  \"train_wape\": 7.66\n}"},"description":"Marks a previously started forecast run as succeeded. `train_wape` is optional at completion; use the train WAPE endpoint to backfill it later.","header":[{"key":"Content-Type","value":"application/json"}],"method":"PATCH","url":{"host":["{{base_url}}"],"path":["api","v1","forecast_runs",":id","complete"],"query":[],"raw":"{{base_url}}/api/v1/forecast_runs/:id/complete","variable":[{"description":"The forecast run id returned by the start endpoint","key":"id","value":""}]}}},{"name":"Record the failure of a forecast run","request":{"body":{"mode":"raw","options":{"raw":{"language":"json"}},"raw":"{\n  \"ended_at\": \"2026-04-27T09:14:32Z\",\n  \"error_message\": \"Forecast pipeline timed out\"\n}"},"description":"Marks a previously started forecast run as failed and optionally records an error message.","header":[{"key":"Content-Type","value":"application/json"}],"method":"PATCH","url":{"host":["{{base_url}}"],"path":["api","v1","forecast_runs",":id","fail"],"query":[],"raw":"{{base_url}}/api/v1/forecast_runs/:id/fail","variable":[{"description":"The forecast run id returned by the start endpoint","key":"id","value":""}]}}},{"name":"Backfill forecast train WAPE","request":{"body":{"mode":"raw","options":{"raw":{"language":"json"}},"raw":"{\n  \"train_wape\": 7.66\n}"},"description":"Updates the train WAPE for a succeeded forecast run without changing the completion timestamp.","header":[{"key":"Content-Type","value":"application/json"}],"method":"PATCH","url":{"host":["{{base_url}}"],"path":["api","v1","forecast_runs",":id","train_wape"],"query":[],"raw":"{{base_url}}/api/v1/forecast_runs/:id/train_wape","variable":[{"description":"The forecast run id returned by the start endpoint","key":"id","value":""}]}}},{"name":"Get forecast runs","request":{"description":"Returns forecast runs for the authenticated organisation. Results are sorted by `started_at` descending.","header":[],"method":"GET","url":{"host":["{{base_url}}"],"path":["api","v1","forecasts"],"query":[{"description":"Number of elements per page","disabled":true,"key":"page_size","value":""},{"description":"Number of the page","disabled":true,"key":"page","value":""},{"description":"Filter by forecast target","disabled":true,"key":"target","value":""},{"description":"Filter to runs started on or after this ISO8601 timestamp","disabled":true,"key":"started_after","value":""},{"description":"Filter to runs started on or before this ISO8601 timestamp","disabled":true,"key":"started_before","value":""},{"description":"Filter by status","disabled":true,"key":"status","value":""},{"description":"Filter by train WAPE presence","disabled":true,"key":"train_wape","value":""}],"raw":"{{base_url}}/api/v1/forecasts","variable":[]}}},{"name":"Get a forecast run","request":{"description":"","header":[],"method":"GET","url":{"host":["{{base_url}}"],"path":["api","v1","forecasts",":id"],"query":[],"raw":"{{base_url}}/api/v1/forecasts/:id","variable":[{"description":"The forecast run id","key":"id","value":""}]}}}],"name":"ForecastRuns"},{"description":null,"item":[{"name":"Get a list of holiday adjustments","request":{"description":"Returns a list of holiday adjustments sorted by creation date. Allows filtering by `user_id`.","header":[],"method":"GET","url":{"host":["{{base_url}}"],"path":["api","v1","holiday_adjustments"],"query":[{"description":"Number of elements per page","disabled":true,"key":"page_size","value":""},{"description":"Number of the page","disabled":true,"key":"page","value":""},{"description":"The user ID to filter by","disabled":true,"key":"user_id","value":""}],"raw":"{{base_url}}/api/v1/holiday_adjustments","variable":[]}}},{"name":"Create a holiday adjustment","request":{"body":{"mode":"raw","options":{"raw":{"language":"json"}},"raw":"{\n  \"active_at\": \"2024-10-25\",\n  \"amount\": 1,\n  \"contract_id\": \"4f5c2a36-8f6e-4a0a-9d8e-2b1c7f3e6a51\",\n  \"reason\": \"reason\",\n  \"type\": \"allowance\",\n  \"user_id\": \"0a727402-fcae-44ee-bb6e-b7d88e334e87\",\n  \"variation\": \"add\"\n}"},"description":"Create a holiday adjustment","header":[{"key":"Content-Type","value":"application/json"}],"method":"POST","url":{"host":["{{base_url}}"],"path":["api","v1","holiday_adjustments"],"query":[],"raw":"{{base_url}}/api/v1/holiday_adjustments","variable":[]}}}],"name":"HolidayAdjustments"},{"description":null,"item":[{"name":"Get a user's holiday balance","request":{"description":"Retrieve the holiday balance for a specific user.","header":[],"method":"GET","url":{"host":["{{base_url}}"],"path":["api","v1","holiday_balance",":user_id"],"query":[{"description":"The date for which to show holiday balance","disabled":true,"key":"date","value":""},{"description":"The Sona unique identifier of the contract the request is about, from `contract_id` on `GET /api/v1/employment_periods`. Only used by organisations with overlapping employment periods enabled. Required when the user holds employment periods on several contracts covering the requested date; without it the only contract covering that date is used. A contract whose employment periods have ended still reads its own absence year covering the date.","disabled":true,"key":"contract_id","value":""}],"raw":"{{base_url}}/api/v1/holiday_balance/:user_id","variable":[{"description":"The Sona unique identifier of the user.","key":"user_id","value":""}]}}}],"name":"HolidayBalance"},{"description":null,"item":[{"name":"Preview rule interpolation across a date range","request":{"body":{"mode":"raw","options":{"raw":{"language":"json"}},"raw":"{\n  \"from_date\": \"2024-06-15\",\n  \"rules\": [\n    {\n      \"master_shift_type_id\": \"550e8400-e29b-41d4-a716-446655440002\",\n      \"metric_id\": \"550e8400-e29b-41d4-a716-446655440003\",\n      \"rule_params\": {\n        \"ratio\": \"{avg_hourly_footfall} / 20\"\n      },\n      \"rule_type\": \"inflexible_demand_linear\"\n    }\n  ],\n  \"to_date\": \"2024-07-15\"\n}"},"description":"Resolves attribute expressions in productivity rules for each date in a range.\nReturns concrete rule parameters grouped by date, showing how scheduled attribute\nchanges affect rule interpolation over time.\n\n**Rules source:**\n- If `rules` is provided, those rules are interpolated.\n- If `rules` is omitted, rules are loaded from the org unit's productivity config.\n\n**Date range limit:** `to_date - from_date` must not exceed 90 days.\n","header":[{"key":"Content-Type","value":"application/json"}],"method":"POST","url":{"host":["{{base_url}}"],"path":["api","v1","org_units",":org_unit_id","productivity","interpolation_preview"],"query":[],"raw":"{{base_url}}/api/v1/org_units/:org_unit_id/productivity/interpolation_preview","variable":[{"description":"UUID of the organisational unit","key":"org_unit_id","value":""}]}}}],"name":"InterpolationPreview"},{"description":null,"item":[{"name":"Get a list of jobs","request":{"description":"A job represents a role or position within the organisation. Jobs can be archived when no longer in use. Use the archived query parameter to filter by active or archived jobs.","header":[],"method":"GET","url":{"host":["{{base_url}}"],"path":["api","v1","jobs"],"query":[{"description":"Number of elements per page","disabled":true,"key":"page_size","value":""},{"description":"Number of the page","disabled":true,"key":"page","value":""},{"description":"Filter by whether the job has been archived or not. If omitted all jobs are returned.","disabled":true,"key":"archived","value":""}],"raw":"{{base_url}}/api/v1/jobs","variable":[]}}},{"name":"Get an individual job","request":{"description":"Get an individual job. See the job listing endpoint for a description of jobs.","header":[],"method":"GET","url":{"host":["{{base_url}}"],"path":["api","v1","jobs",":job_id"],"query":[],"raw":"{{base_url}}/api/v1/jobs/:job_id","variable":[{"description":"Sona unique identifier of the job","key":"job_id","value":""}]}}}],"name":"Jobs"},{"description":null,"item":[{"name":"Get a list of levels","request":{"description":"Levels represent a hierarchical classification within an organisation, such as seniority bands or pay grades. Levels can be nested via a parent reference to form a tree structure.","header":[],"method":"GET","url":{"host":["{{base_url}}"],"path":["api","v1","levels"],"query":[{"description":"Number of elements per page","disabled":true,"key":"page_size","value":""},{"description":"Number of the page","disabled":true,"key":"page","value":""}],"raw":"{{base_url}}/api/v1/levels","variable":[]}}},{"name":"Get an individual level","request":{"description":"Get an individual level. See the level listing endpoint for a description of levels","header":[],"method":"GET","url":{"host":["{{base_url}}"],"path":["api","v1","levels",":level_id"],"query":[],"raw":"{{base_url}}/api/v1/levels/:level_id","variable":[{"description":"Sona unique identifier of the level","key":"level_id","value":""}]}}}],"name":"Levels"},{"description":null,"item":[{"name":"Get a list of locked periods","request":{"description":"Returns locked periods for the organisation, optionally filtered by date range and/or location. A locked period represents a time range during which the roster for a location is locked and no further changes can be made. Requires the period locking feature to be enabled for the organisation.","header":[],"method":"GET","url":{"host":["{{base_url}}"],"path":["api","v1","locked_periods"],"query":[{"description":"Number of elements per page","disabled":true,"key":"page_size","value":""},{"description":"Number of the page","disabled":true,"key":"page","value":""},{"description":"Start of the date range to filter by (inclusive). in the following ISO 8601 UTC format: 2019-04-20T07:47:58Z (`YYYY-MM-DDTHH:mm:SSZ`)","disabled":true,"key":"start_datetime","value":""},{"description":"End of the date range to filter by (inclusive). in the following ISO 8601 UTC format: 2019-04-20T07:47:58Z (`YYYY-MM-DDTHH:mm:SSZ`)","disabled":true,"key":"end_datetime","value":""},{"description":"Filter to specific location (org unit) IDs. When omitted, all locations are returned.","disabled":true,"key":"location_ids","value":""}],"raw":"{{base_url}}/api/v1/locked_periods","variable":[]}}}],"name":"LockedPeriods"},{"description":null,"item":[{"name":"Lists per-customer metric calculations","request":{"description":"Returns every metric calculation belonging to the organisation, deduplicated by formula content. Each entry includes an `applied_at` array listing the org_units (one per restaurant / location) that use that exact calculation. When the same name maps to different formulas across configs — or differs in `binding_type` or `filter` of any variable — each variant appears as a separate entry with disjoint `applied_at` lists. Per-config display flags (`show_on_roster`, `key_metric`, etc.) are intentionally omitted. Each entry carries a normalised `ast` so consumers can evaluate the formula without parsing the Sona DSL themselves; calculations whose formulas use syntax outside the supported grammar are omitted from the response (with a server-side log) rather than served partial — see the `ast` schema for the supported grammar.","header":[],"method":"GET","url":{"host":["{{base_url}}"],"path":["api","v1","orgs",":organisation_id","metric-calculations"],"query":[],"raw":"{{base_url}}/api/v1/orgs/:organisation_id/metric-calculations","variable":[{"description":"Sona unique identifier of the organisation. Must match the bearer token's organisation.","key":"organisation_id","value":""}]}}}],"name":"MetricCalculations"},{"description":null,"item":[{"name":"Get a list of Metrics","request":{"description":"List the metric definitions configured for the organisation. Use this to resolve a metric's `id` for the `metric_id` filter on `GET /api/v1/metric_values` and for the `/api/v1/metrics/{metric_id}/store` endpoints, rather than hardcoding metric ids.\n\nMetrics are configured per organisation and `name` is customer-defined, so `name` is not stable across organisations. Where Sona recognises a metric as one of its standard ones, `type` carries that meaning from a fixed vocabulary and is stable; `type` is null for metrics the customer defined themselves, so match on `id` and fall back to `name` for those.","header":[],"method":"GET","url":{"host":["{{base_url}}"],"path":["api","v1","metrics"],"query":[{"description":"Number of elements per page","disabled":true,"key":"page_size","value":""},{"description":"Number of the page","disabled":true,"key":"page","value":""}],"raw":"{{base_url}}/api/v1/metrics","variable":[]}}},{"name":"Store the values of a given metric for certain times","request":{"body":{"mode":"raw","options":{"raw":{"language":"json"}},"raw":"[\n  {\n    \"timestamp\": \"2024-06-15T07:00:00Z\",\n    \"value\": 12.5\n  }\n]"},"description":"Store the values of a given metric for certain times","header":[{"key":"Content-Type","value":"application/json"}],"method":"POST","url":{"host":["{{base_url}}"],"path":["api","v1","metrics",":metric_id","store"],"query":[{"description":"The org unit id","disabled":false,"key":"org_unit_id","value":""},{"description":"The type of the metric","disabled":false,"key":"type","value":""}],"raw":"{{base_url}}/api/v1/metrics/:metric_id/store?org_unit_id=&type=","variable":[{"description":"Metric id","key":"metric_id","value":""}]}}},{"name":"Store metric values for multiple org units in a single transaction","request":{"body":{"mode":"raw","options":{"raw":{"language":"json"}},"raw":"{\n  \"data\": {\n    \"actual\": {\n      \"org_unit_id_1\": [\n        {\n          \"timestamp\": \"2020-01-01T07:00:00Z\",\n          \"value\": 1.0\n        }\n      ]\n    },\n    \"system_forecasted\": {\n      \"org_unit_id_2\": [\n        {\n          \"timestamp\": \"2020-01-01T07:00:00Z\",\n          \"value\": 2.0\n        }\n      ]\n    }\n  }\n}"},"description":"Store metric values for multiple org units. Either all values are stored or none (all-or-nothing).","header":[{"key":"Content-Type","value":"application/json"}],"method":"POST","url":{"host":["{{base_url}}"],"path":["api","v1","metrics",":metric_id","store_bulk"],"query":[],"raw":"{{base_url}}/api/v1/metrics/:metric_id/store_bulk","variable":[{"description":"Metric id","key":"metric_id","value":""}]}}},{"name":"Store historical metric values with a custom current_timestamp","request":{"body":{"mode":"raw","options":{"raw":{"language":"json"}},"raw":"[\n  {\n    \"timestamp\": \"2024-06-15T07:00:00Z\",\n    \"value\": 12.5\n  }\n]"},"description":"Store metric values for historical backfill. Unlike /store, this endpoint requires a current_timestamp parameter to specify when the data was recorded.","header":[{"key":"Content-Type","value":"application/json"}],"method":"POST","url":{"host":["{{base_url}}"],"path":["api","v1","metrics",":metric_id","store_historical"],"query":[{"description":"The org unit id","disabled":false,"key":"org_unit_id","value":""},{"description":"The type of the metric","disabled":false,"key":"type","value":""},{"description":"The timestamp when this data was recorded (ISO8601 format, must be in the past)","disabled":false,"key":"current_timestamp","value":""}],"raw":"{{base_url}}/api/v1/metrics/:metric_id/store_historical?org_unit_id=&type=&current_timestamp=","variable":[{"description":"Metric id","key":"metric_id","value":""}]}}},{"name":"Store historical metric values for multiple org units with a custom timestamp","request":{"body":{"mode":"raw","options":{"raw":{"language":"json"}},"raw":"{\n  \"data\": {\n    \"actual\": {\n      \"org_unit_id_1\": [\n        {\n          \"timestamp\": \"2020-01-01T07:00:00Z\",\n          \"value\": 1.0\n        }\n      ]\n    },\n    \"system_forecasted\": {\n      \"org_unit_id_2\": [\n        {\n          \"timestamp\": \"2020-01-01T07:00:00Z\",\n          \"value\": 2.0\n        }\n      ]\n    }\n  }\n}"},"description":"Store metric values for multiple org units with a custom current_timestamp for historical backfill. Similar to /store_bulk but requires a current_timestamp parameter. Either all values are stored or none (all-or-nothing transaction).","header":[{"key":"Content-Type","value":"application/json"}],"method":"POST","url":{"host":["{{base_url}}"],"path":["api","v1","metrics",":metric_id","store_historical_bulk"],"query":[{"description":"The timestamp when this data was recorded (ISO8601 format, must be in the past)","disabled":false,"key":"current_timestamp","value":""}],"raw":"{{base_url}}/api/v1/metrics/:metric_id/store_historical_bulk?current_timestamp=","variable":[{"description":"Metric id","key":"metric_id","value":""}]}}},{"name":"Get the latest timestamp of a given metric","request":{"description":"Returns the latest timestamp recorded for the specified metric and org unit. If nothing has been recorded, or the metric or org unit does not exist, `timestamp` is null.","header":[],"method":"GET","url":{"host":["{{base_url}}"],"path":["api","v1","metrics",":metric_id",":org_unit_id","latest_timestamp"],"query":[{"description":"The type of the metric","disabled":true,"key":"type","value":""}],"raw":"{{base_url}}/api/v1/metrics/:metric_id/:org_unit_id/latest_timestamp","variable":[{"description":"Metric id","key":"metric_id","value":""},{"description":"The org unit id","key":"org_unit_id","value":""}]}}}],"name":"Metrics"},{"description":null,"item":[{"name":"Get a list of Metric Values","request":{"description":"Read recorded metric values — actuals, forecasts and budgets — for the organisation.\n\n**Pagination is cursor-based, not page-based.** Unlike other endpoints in this API this one does not accept a `page` parameter. Make the first request without `cursor`, then pass the `next_cursor` from each response as the `cursor` of the next request. When `next_cursor` is `null` you have reached the end of the result set; a page may hold fewer than `page_size` entries while more follow, so do not stop early. Treat the cursor as opaque — its format is not part of this contract.\n\nA cursor is a position within one specific result set. It is tied to the `from`, `to`, `metric_id`, `org_unit_id`, `type` and `current` it was issued for, and replaying it against a different combination returns 422 rather than silently skipping rows. To move a window forward, start a new walk without a cursor.\n\nValues are returned grouped by org unit and ordered by timestamp within each org unit, not in global chronological order across sites.\n\n`from` and `to` are required and are interpreted as UTC midnight, so the window is `timestamp >= from` and `timestamp < to`. Note this is a UTC window, not the organisation's business day.\n\nOnly unfiltered values are returned. Where a metric is broken down by a filter, Sona stores the per-filter values alongside the unfiltered total; this endpoint returns the total, so values can be summed without double counting.\n\n`metric_id` is required — call `GET /api/v1/metrics` first to resolve the ids you need, then pass up to 50 of them per request.\n\nA walk is not a consistent snapshot. Values are written while you page, and a value that is re-recorded mid-walk may be returned as a superseded version or not at all on that walk. For incremental sync, re-read the most recent days on each run rather than assuming a completed walk was complete.\n\nReads are rate limited per organisation, and only a couple may run at once — page sequentially rather than in parallel. A 429 carries a `Retry-After` header; wait that long and reissue the same request, cursor included. A 503 means the read could not be served right now and is likewise safe to retry as-is.","header":[],"method":"GET","url":{"host":["{{base_url}}"],"path":["api","v1","metric_values"],"query":[{"description":"Start of the window (inclusive), as YYYY-MM-DD, interpreted as UTC midnight","disabled":false,"key":"from","value":""},{"description":"End of the window (exclusive), as YYYY-MM-DD, interpreted as UTC midnight. May be at most 31 days after `from`.","disabled":false,"key":"to","value":""},{"description":"The metric ids to return values for, from `GET /api/v1/metrics`. Repeat the parameter (`metric_id[]=a&metric_id[]=b`) or pass a comma-separated list. Required, and at most 50 — an unfiltered read of this table cannot be served efficiently.","disabled":false,"key":"metric_id","value":""},{"description":"Restrict to these org unit (site) ids. Repeat the parameter or pass a comma-separated list. Omit to return all sites. At most 100.","disabled":true,"key":"org_unit_id","value":""},{"description":"Restrict to these value types. Repeat the parameter or pass a comma-separated list. Omit to return all types.","disabled":true,"key":"type","value":""},{"description":"Defaults to true: only the latest recorded version of each value is returned. Sona keeps the full history of every value; pass `false` to include superseded versions as well.","disabled":true,"key":"current","value":""},{"description":"Number of values per page. Defaults to 1000, maximum 10000.","disabled":true,"key":"page_size","value":""},{"description":"The `next_cursor` from the previous response, with every other parameter unchanged. Omit for the first page.","disabled":true,"key":"cursor","value":""}],"raw":"{{base_url}}/api/v1/metric_values?from=&to=&metric_id=","variable":[]}}}],"name":"MetricValues"},{"description":null,"item":[{"name":"Gets the organisation calendar","request":{"description":"Returns the calendar settings of the API key's organisation: the day its week starts on, the time its business day starts, and the start of its fiscal year. Use them to bucket days, weeks and fiscal years the way the organisation does.","header":[],"method":"GET","url":{"host":["{{base_url}}"],"path":["api","v1","organisation","calendar"],"query":[],"raw":"{{base_url}}/api/v1/organisation/calendar","variable":[]}}}],"name":"OrganisationCalendar"},{"description":null,"item":[{"name":"List all org attributes","request":{"description":"Returns all attribute definitions for the authenticated organisation.","header":[],"method":"GET","url":{"host":["{{base_url}}"],"path":["api","v1","org_attributes"],"query":[{"description":"Number of elements per page","disabled":true,"key":"page_size","value":""},{"description":"Number of the page","disabled":true,"key":"page","value":""}],"raw":"{{base_url}}/api/v1/org_attributes","variable":[]}}},{"name":"Create an org attribute","request":{"body":{"mode":"raw","options":{"raw":{"language":"json"}},"raw":"{\n  \"description\": \"The time the location opens for service\",\n  \"label\": \"Opening Time\",\n  \"slug\": \"opening_time\",\n  \"type\": \"time\",\n  \"value\": \"07:00\"\n}"},"description":"Creates a new attribute definition for the organisation.","header":[{"key":"Content-Type","value":"application/json"}],"method":"POST","url":{"host":["{{base_url}}"],"path":["api","v1","org_attributes"],"query":[],"raw":"{{base_url}}/api/v1/org_attributes","variable":[]}}},{"name":"Get an org attribute","request":{"description":"Returns a single attribute definition by ID.","header":[],"method":"GET","url":{"host":["{{base_url}}"],"path":["api","v1","org_attributes",":id"],"query":[],"raw":"{{base_url}}/api/v1/org_attributes/:id","variable":[{"description":"Org attribute ID","key":"id","value":""}]}}},{"name":"Update an org attribute","request":{"body":{"mode":"raw","options":{"raw":{"language":"json"}},"raw":"{\n  \"description\": \"The time the location opens for service each day\",\n  \"label\": \"Opening Time (Updated)\",\n  \"type\": \"time\",\n  \"value\": \"08:00\"\n}"},"description":"Updates an existing attribute definition. Slug cannot be changed.","header":[{"key":"Content-Type","value":"application/json"}],"method":"PUT","url":{"host":["{{base_url}}"],"path":["api","v1","org_attributes",":id"],"query":[],"raw":"{{base_url}}/api/v1/org_attributes/:id","variable":[{"description":"Org attribute ID","key":"id","value":""}]}}},{"name":"Delete an org attribute","request":{"description":"Deletes an attribute definition. Fails if the attribute is used by productivity rulesets. Cascades deletion to all org unit attribute overrides.","header":[],"method":"DELETE","url":{"host":["{{base_url}}"],"path":["api","v1","org_attributes",":id"],"query":[],"raw":"{{base_url}}/api/v1/org_attributes/:id","variable":[{"description":"Org attribute ID","key":"id","value":""}]}}}],"name":"OrgAttributes"},{"description":null,"item":[{"name":"Batch query org attribute values","request":{"body":{"mode":"raw","options":{"raw":{"language":"json"}},"raw":"{\n  \"attribute_slugs\": [\n    \"opening_time\",\n    \"closing_time\"\n  ],\n  \"end_date\": \"2026-02-03\",\n  \"org_unit_ids\": [\n    \"e27ad021-af0e-4ccf-95e8-1c7c84656c93\",\n    \"f38be132-bf1f-5dd0-a6f9-2d8d95767da4\"\n  ],\n  \"start_date\": \"2026-02-01\"\n}"},"description":"Returns the resolved value of each requested attribute for each org unit on each date in the given range. Values are resolved using the most specific org-unit-level override, falling back to the organisation-level default. A value of null means the attribute is not configured, while the string \"excluded\" means the org unit is explicitly excluded from that attribute. If an org unit has no data for any requested attribute, its entry is null.","header":[{"key":"Content-Type","value":"application/json"}],"method":"POST","url":{"host":["{{base_url}}"],"path":["api","v1","org_attributes","batch_query"],"query":[],"raw":"{{base_url}}/api/v1/org_attributes/batch_query","variable":[]}}}],"name":"OrgAttributesBatch"},{"description":null,"item":[{"name":"List org unit attributes","request":{"description":"Returns all attribute overrides for a given org unit.","header":[],"method":"GET","url":{"host":["{{base_url}}"],"path":["api","v1","org_unit_attributes"],"query":[{"description":"Number of elements per page","disabled":true,"key":"page_size","value":""},{"description":"Number of the page","disabled":true,"key":"page","value":""},{"description":"Org unit ID (required)","disabled":false,"key":"org_unit_id","value":""}],"raw":"{{base_url}}/api/v1/org_unit_attributes?org_unit_id=","variable":[]}}},{"name":"Create an org unit attribute","request":{"body":{"mode":"raw","options":{"raw":{"language":"json"}},"raw":"{\n  \"end_date\": \"2024-12-31\",\n  \"excluded\": false,\n  \"org_attribute_id\": \"b2c3d4e5-6789-4abc-bcde-222222222222\",\n  \"org_unit_id\": \"a1b2c3d4-5678-4def-abcd-111111111111\",\n  \"start_date\": \"2024-06-15\",\n  \"value\": \"145.5\"\n}"},"description":"Creates a new attribute override for an org unit. Optionally schedule the value with start_date and end_date (both inclusive).","header":[{"key":"Content-Type","value":"application/json"}],"method":"POST","url":{"host":["{{base_url}}"],"path":["api","v1","org_unit_attributes"],"query":[],"raw":"{{base_url}}/api/v1/org_unit_attributes","variable":[]}}},{"name":"Get an org unit attribute","request":{"description":"Returns a single org unit attribute override by ID.","header":[],"method":"GET","url":{"host":["{{base_url}}"],"path":["api","v1","org_unit_attributes",":id"],"query":[],"raw":"{{base_url}}/api/v1/org_unit_attributes/:id","variable":[{"description":"Org unit attribute ID","key":"id","value":""}]}}},{"name":"Update an org unit attribute","request":{"body":{"mode":"raw","options":{"raw":{"language":"json"}},"raw":"{\n  \"end_date\": \"2025-03-31\",\n  \"excluded\": false,\n  \"start_date\": \"2024-07-01\",\n  \"value\": \"160.0\"\n}"},"description":"Updates an existing org unit attribute override. Fails with 422 when the change would leave a required attribute unresolved — excluding the value (which masks the org-level default) or shrinking its active span — for productivity rulesets assigned to the org unit.","header":[{"key":"Content-Type","value":"application/json"}],"method":"PUT","url":{"host":["{{base_url}}"],"path":["api","v1","org_unit_attributes",":id"],"query":[],"raw":"{{base_url}}/api/v1/org_unit_attributes/:id","variable":[{"description":"Org unit attribute ID","key":"id","value":""}]}}},{"name":"Delete an org unit attribute","request":{"description":"Deletes an org unit attribute override. The org unit will fall back to the organisation-level default value. Fails with 422 when the value has no org-level default and is required by productivity rulesets assigned to the org unit (the delete would leave those rules unable to compute).","header":[],"method":"DELETE","url":{"host":["{{base_url}}"],"path":["api","v1","org_unit_attributes",":id"],"query":[],"raw":"{{base_url}}/api/v1/org_unit_attributes/:id","variable":[{"description":"Org unit attribute ID","key":"id","value":""}]}}}],"name":"OrgUnitAttributes"},{"description":null,"item":[{"name":"Get an org unit's location","request":{"description":"Returns the location of an org unit","header":[],"method":"GET","url":{"host":["{{base_url}}"],"path":["api","v1","org_units",":org_unit_id","location"],"query":[],"raw":"{{base_url}}/api/v1/org_units/:org_unit_id/location","variable":[{"description":"Sona unique identifier of the org unit","key":"org_unit_id","value":""}]}}},{"name":"Create or update an org unit's location","request":{"body":{"mode":"raw","options":{"raw":{"language":"json"}},"raw":"{\n  \"address_line_1\": \"1 Bridge Street\",\n  \"city\": \"London\",\n  \"country_code\": \"GB\",\n  \"latitude\": 51.5007,\n  \"longitude\": -0.1246,\n  \"name\": \"Head Office\",\n  \"postcode\": \"SW1A0AA\"\n}"},"description":"Create or update an org unit's location.","header":[{"key":"Content-Type","value":"application/json"}],"method":"POST","url":{"host":["{{base_url}}"],"path":["api","v1","org_units",":org_unit_id","location"],"query":[],"raw":"{{base_url}}/api/v1/org_units/:org_unit_id/location","variable":[{"description":"Sona unique identifier of the org unit","key":"org_unit_id","value":""}]}}},{"name":"Delete the org unit's location","request":{"description":"Delete the org unit's location","header":[],"method":"DELETE","url":{"host":["{{base_url}}"],"path":["api","v1","org_units",":org_unit_id","location"],"query":[],"raw":"{{base_url}}/api/v1/org_units/:org_unit_id/location","variable":[{"description":"Sona unique identifier of the org unit","key":"org_unit_id","value":""}]}}}],"name":"OrgUnitLocation"},{"description":null,"item":[{"name":"Get a list of Org Units","request":{"description":"An org unit in Sona represents a single organisation unit of a business. So for example if a business is structured as Head Office -> Regions -> Locations -> Departments then an org unit could be any one of those things. Which one it is can be identified from the `org_unit_type` field. Every org unit but one for an organisation will have a `parent_org_unit` which can be used to reconstruct the hierarchy.\n\n**Important**: By default, only base entities (typically the lowest-level units such as Sites or Departments) are returned. To retrieve the full hierarchy including parent org units (e.g. Regions, Areas), you must pass `base_only=false`. Example: `GET /api/v1/org_units?base_only=false`\n\n**Pagination**: Results are paginated. Use the `page` and `page_size` query parameters to navigate. The default page size is 10. Note: the parameter name is `page` (not `page_number`). The response includes `page_number`, `page_size`, `total_pages`, and `total_entries` metadata to assist with iteration.","header":[],"method":"GET","url":{"host":["{{base_url}}"],"path":["api","v1","org_units"],"query":[{"description":"Number of elements per page","disabled":true,"key":"page_size","value":""},{"description":"Number of the page","disabled":true,"key":"page","value":""},{"description":"The external ids to filter by. Only org units with a matching external connection are returned.","disabled":true,"key":"external_ids","value":""},{"description":"Whether only base entities should be returned. **Defaults to `true`**, which means only the lowest-level org units (e.g. Sites, Departments) are returned. Set to `false` to include all org units in the hierarchy, including parent units such as Regions and Areas. This is required if you need to resolve `parent_org_unit` references.","disabled":true,"key":"base_only","value":""}],"raw":"{{base_url}}/api/v1/org_units","variable":[]}}},{"name":"Create an Org Unit","request":{"body":{"mode":"raw","options":{"raw":{"language":"json"}},"raw":"{\n  \"accounting_cost_code\": \"MW-001\",\n  \"average_hourly_rate\": 14.5,\n  \"external_connections\": [\n    {\n      \"external_id\": \"EXT-MW-001\"\n    }\n  ],\n  \"is_base_entity\": true,\n  \"name\": \"Maple Ward\",\n  \"org_unit_type_id\": \"c9d80598-8223-4836-875d-f6dd9552a77f\",\n  \"parent_id\": \"e27ad021-af0e-4ccf-95e8-1c7c84656c93\",\n  \"paycaptain_company_id\": \"PC-1234\",\n  \"public_holidays\": [\n    \"a1b2c3d4-e5f6-7890-abcd-ef1234567890\"\n  ]\n}"},"description":"Create an Org Unit","header":[{"key":"Content-Type","value":"application/json"}],"method":"POST","url":{"host":["{{base_url}}"],"path":["api","v1","org_units"],"query":[],"raw":"{{base_url}}/api/v1/org_units","variable":[]}}},{"name":"Get an individual org unit","request":{"description":"Get an individual org unit. See the org unit listing endpoint for a description of org units","header":[],"method":"GET","url":{"host":["{{base_url}}"],"path":["api","v1","org_units",":org_unit_id"],"query":[],"raw":"{{base_url}}/api/v1/org_units/:org_unit_id","variable":[{"description":"Sona unique identifier of the org_unit","key":"org_unit_id","value":""}]}}},{"name":"Update an Org Unit","request":{"body":{"mode":"raw","options":{"raw":{"language":"json"}},"raw":"{\n  \"accounting_cost_code\": \"OW-002\",\n  \"average_hourly_rate\": 15.75,\n  \"external_connections\": [\n    {\n      \"external_id\": \"EXT-OW-002\"\n    }\n  ],\n  \"is_base_entity\": true,\n  \"name\": \"Oak Ward\",\n  \"org_unit_type_id\": \"c9d80598-8223-4836-875d-f6dd9552a77f\",\n  \"parent_id\": \"e27ad021-af0e-4ccf-95e8-1c7c84656c93\",\n  \"paycaptain_company_id\": \"PC-5678\"\n}"},"description":"Update an Org Unit","header":[{"key":"Content-Type","value":"application/json"}],"method":"PUT","url":{"host":["{{base_url}}"],"path":["api","v1","org_units",":org_unit_id"],"query":[],"raw":"{{base_url}}/api/v1/org_units/:org_unit_id","variable":[{"description":"The Sona unique identifier of org unit to update","key":"org_unit_id","value":""}]}}},{"name":"Set public holidays for the org unit","request":{"body":{"mode":"raw","options":{"raw":{"language":"json"}},"raw":"{\n  \"public_holidays\": [\n    \"a1b2c3d4-e5f6-7890-abcd-ef1234567890\",\n    \"b2c3d4e5-f6a7-8901-bcde-f12345678901\"\n  ]\n}"},"description":"Set public holidays for the org unit","header":[{"key":"Content-Type","value":"application/json"}],"method":"POST","url":{"host":["{{base_url}}"],"path":["api","v1","org_units",":org_unit_id","public_holidays"],"query":[],"raw":"{{base_url}}/api/v1/org_units/:org_unit_id/public_holidays","variable":[{"description":"Sona unique identifier of the org unit","key":"org_unit_id","value":""}]}}},{"name":"Remove selected public holidays from the org unit public holidays list","request":{"body":{"mode":"raw","options":{"raw":{"language":"json"}},"raw":"{\n  \"public_holidays\": [\n    \"a1b2c3d4-e5f6-7890-abcd-ef1234567890\",\n    \"b2c3d4e5-f6a7-8901-bcde-f12345678901\"\n  ]\n}"},"description":"Remove selected public holidays from the org unit public holidays list","header":[{"key":"Content-Type","value":"application/json"}],"method":"DELETE","url":{"host":["{{base_url}}"],"path":["api","v1","org_units",":org_unit_id","public_holidays"],"query":[],"raw":"{{base_url}}/api/v1/org_units/:org_unit_id/public_holidays","variable":[{"description":"Sona unique identifier of the org unit","key":"org_unit_id","value":""}]}}}],"name":"OrgUnits"},{"description":null,"item":[{"name":"Get a list of Org Unit Types","request":{"description":"Get a list of Org Unit Types","header":[],"method":"GET","url":{"host":["{{base_url}}"],"path":["api","v1","org_unit_types"],"query":[{"description":"Number of elements per page","disabled":true,"key":"page_size","value":""},{"description":"Number of the page","disabled":true,"key":"page","value":""}],"raw":"{{base_url}}/api/v1/org_unit_types","variable":[]}}},{"name":"Create an Org Unit Type","request":{"body":{"mode":"raw","options":{"raw":{"language":"json"}},"raw":"{\n  \"name\": \"Department\",\n  \"parent_id\": \"c9d80598-8223-4836-875d-f6dd9552a77f\"\n}"},"description":"Create an Org Unit Type","header":[{"key":"Content-Type","value":"application/json"}],"method":"POST","url":{"host":["{{base_url}}"],"path":["api","v1","org_unit_types"],"query":[],"raw":"{{base_url}}/api/v1/org_unit_types","variable":[]}}},{"name":"Get an individual org unit type","request":{"description":"Get an individual org unit type. See the listing endpoint for a description of org unit types","header":[],"method":"GET","url":{"host":["{{base_url}}"],"path":["api","v1","org_unit_types",":org_unit_type_id"],"query":[],"raw":"{{base_url}}/api/v1/org_unit_types/:org_unit_type_id","variable":[{"description":"Sona unique identifier of the org_unit_type","key":"org_unit_type_id","value":""}]}}}],"name":"OrgUnitTypes"},{"description":null,"item":[{"name":"List pay periods for a pay group","request":{"description":"Returns the pay schedule (pay periods) for the given pay group, ordered by start date descending.","header":[],"method":"GET","url":{"host":["{{base_url}}"],"path":["api","v1","pay_groups",":pay_group_id","pay_periods"],"query":[{"description":"Number of elements per page","disabled":true,"key":"page_size","value":""},{"description":"Number of the page","disabled":true,"key":"page","value":""},{"description":"Filter pay periods with start_date on or after this date (ISO 8601, e.g. 2026-01-01)","disabled":true,"key":"from_date","value":""},{"description":"Filter pay periods with start_date on or before this date (ISO 8601, e.g. 2026-12-31)","disabled":true,"key":"to_date","value":""},{"description":"Filter by pay period state: \"open\" or \"closed\"","disabled":true,"key":"state","value":""}],"raw":"{{base_url}}/api/v1/pay_groups/:pay_group_id/pay_periods","variable":[{"description":"The Sona unique identifier of the pay group.","key":"pay_group_id","value":""}]}}}],"name":"PayGroupPayPeriods"},{"description":null,"item":[{"name":"Get a list of pay groups","request":{"description":"List pay groups for the current organisation","header":[],"method":"GET","url":{"host":["{{base_url}}"],"path":["api","v1","pay_groups"],"query":[{"description":"Number of elements per page","disabled":true,"key":"page_size","value":""},{"description":"Number of the page","disabled":true,"key":"page","value":""}],"raw":"{{base_url}}/api/v1/pay_groups","variable":[]}}},{"name":"Get a single pay group","request":{"description":"Get a single pay group data.","header":[],"method":"GET","url":{"host":["{{base_url}}"],"path":["api","v1","pay_groups",":id"],"query":[],"raw":"{{base_url}}/api/v1/pay_groups/:id","variable":[{"description":"The Sona unique identifier of the pay group.","key":"id","value":""}]}}}],"name":"PayGroups"},{"description":null,"item":[{"name":"Get a list of pay lines","request":{"description":"List all pay lines for the current organisation.","header":[],"method":"GET","url":{"host":["{{base_url}}"],"path":["api","v1","pay_lines"],"query":[{"description":"Number of elements per page","disabled":true,"key":"page_size","value":""},{"description":"Number of the page","disabled":true,"key":"page","value":""},{"description":"order results by date (asc or desc). By default is asc.","disabled":true,"key":"order_by_date","value":""},{"description":"The start date time in the following ISO 8601 UTC format: 2019-04-20T07:47:58Z (`YYYY-MM-DDTHH:mm:SSZ`)","disabled":true,"key":"start_datetime","value":""},{"description":"The end date time in the following ISO 8601 UTC format: 2019-04-20T07:47:58Z (`YYYY-MM-DDTHH:mm:SSZ`)","disabled":true,"key":"end_datetime","value":""},{"description":"Type of pay line","disabled":true,"key":"entry_type","value":""},{"description":"Filter by user id","disabled":true,"key":"user_id","value":""}],"raw":"{{base_url}}/api/v1/pay_lines","variable":[]}}}],"name":"PayLines"},{"description":null,"item":[{"name":"List payroll payment/deduction types","request":{"description":"Returns a paginated list of payroll payment and deduction types for the current organisation.","header":[],"method":"GET","url":{"host":["{{base_url}}"],"path":["api","v1","payroll_payment_deduction_types"],"query":[{"description":"Number of elements per page","disabled":true,"key":"page_size","value":""},{"description":"Number of the page","disabled":true,"key":"page","value":""}],"raw":"{{base_url}}/api/v1/payroll_payment_deduction_types","variable":[]}}},{"name":"Create a payroll payment/deduction type","request":{"body":{"mode":"raw","options":{"raw":{"language":"json"}},"raw":"{\n  \"additional_properties\": {\n    \"is_overtime\": true,\n    \"is_regular_pay\": false\n  },\n  \"exclude_from_wage_cost\": false,\n  \"external_type\": \"Overtime\",\n  \"gender_pay_gap\": \"ordinary\",\n  \"holidayable\": true,\n  \"min_wage\": false,\n  \"name\": \"Overtime 1.5x\",\n  \"niable\": true,\n  \"pay_code\": \"OT150\",\n  \"payslip_text\": \"Overtime at time and a half\",\n  \"pensionable\": false,\n  \"taxable\": true,\n  \"type\": \"Payment\"\n}"},"description":"Create a new payroll payment or deduction type for the current organisation.\n\nThe `type` field distinguishes payments from deductions: \"Payment\", \"Deduction\", or \"Cost\".\n\nThe `external_type` field must match the company pay elements in Shape when Sona Pay sync\nis enabled for the organisation; it becomes a required field in that case.\n\nThe `system_pay_code` field is optional and restricted to: final_holiday_pay, holiday_pay, ssp.\nOnly one final_holiday_pay type and one ssp type are allowed per organisation.\n\nWARNING: Changing a pay_code after TGP rules reference it may cause errors in running\nor future TGP jobs.\n","header":[{"key":"Content-Type","value":"application/json"}],"method":"POST","url":{"host":["{{base_url}}"],"path":["api","v1","payroll_payment_deduction_types"],"query":[],"raw":"{{base_url}}/api/v1/payroll_payment_deduction_types","variable":[]}}},{"name":"Get a single payroll payment/deduction type","request":{"description":"Get a single payroll payment or deduction type by its Sona unique identifier.","header":[],"method":"GET","url":{"host":["{{base_url}}"],"path":["api","v1","payroll_payment_deduction_types",":id"],"query":[],"raw":"{{base_url}}/api/v1/payroll_payment_deduction_types/:id","variable":[{"description":"The Sona unique identifier of the payroll payment/deduction type.","key":"id","value":""}]}}},{"name":"Update a payroll payment/deduction type","request":{"body":{"mode":"raw","options":{"raw":{"language":"json"}},"raw":"{\n  \"additional_properties\": {\n    \"is_overtime\": true\n  },\n  \"name\": \"Overtime 2x\",\n  \"payslip_text\": \"Overtime at double time\",\n  \"taxable\": true\n}"},"description":"Update an existing payroll payment or deduction type.\n\nThe `additional_properties` field uses merge semantics: only the keys you provide will be\nupdated; existing keys not included in the request are preserved. Omitting\n`additional_properties` entirely leaves the current value unchanged.\n\nWARNING: Changing a pay_code after TGP rules reference it may cause errors in running\nor future TGP jobs. Changing system_pay_code may affect holiday pay or SSP calculations.\n","header":[{"key":"Content-Type","value":"application/json"}],"method":"PUT","url":{"host":["{{base_url}}"],"path":["api","v1","payroll_payment_deduction_types",":id"],"query":[],"raw":"{{base_url}}/api/v1/payroll_payment_deduction_types/:id","variable":[{"description":"The Sona unique identifier of the payroll payment/deduction type.","key":"id","value":""}]}}}],"name":"PayrollPaymentDeductionTypes"},{"description":null,"item":[{"name":"Get payroll submission statuses for worked shifts","request":{"description":"Returns worked shifts with their payroll submission status and, for shifts still pending submission, whether they need attention (\"unreconciled\") and why. This is the programmatic equivalent of the *Review Payroll Records* / *Pending Submission* view.\n\n`submission_status` is `pending` (not yet approved for payroll) or `submitted` (approved for payroll). `reconciliation_status` is `needs_attention` when the shift has an unresolved payroll issue, otherwise `resolved`. The `exceptions` array lists the reasons a shift needs attention: `pay_query` (an exception flagged on the payroll record), `missing_pay_variant`, `shift_in_progress` (payroll record has no end time), or `missing_pay_record` (no payroll record while time & attendance is required).\n\n`min_start_datetime` and `max_start_datetime` are required and may span at most 31 days.","header":[],"method":"GET","url":{"host":["{{base_url}}"],"path":["api","v1","payroll_submission_statuses"],"query":[{"description":"Number of elements per page","disabled":true,"key":"page_size","value":""},{"description":"Number of the page","disabled":true,"key":"page","value":""},{"description":"Only include shifts starting on or after this time in the following ISO 8601 UTC format: 2019-04-20T07:47:58Z (`YYYY-MM-DDTHH:mm:SSZ`)","disabled":false,"key":"min_start_datetime","value":""},{"description":"Only include shifts starting on or before this time in the following ISO 8601 UTC format: 2019-04-20T07:47:58Z (`YYYY-MM-DDTHH:mm:SSZ`)","disabled":false,"key":"max_start_datetime","value":""},{"description":"Filter by the Sona user id of the employee","disabled":true,"key":"user_id","value":""},{"description":"Filter by one or more org unit (location) ids, comma-separated","disabled":true,"key":"org_unit_ids","value":""},{"description":"Filter by submission status","disabled":true,"key":"submission_status","value":""}],"raw":"{{base_url}}/api/v1/payroll_submission_statuses?min_start_datetime=&max_start_datetime=","variable":[]}}}],"name":"PayrollSubmissionStatuses"},{"description":null,"item":[{"name":"Paginated list of pay variants","request":{"description":"Lists all pay variants associated with an absence type.","header":[],"method":"GET","url":{"host":["{{base_url}}"],"path":["api","v1","absence_types",":absence_type_id","pay_variants"],"query":[{"description":"Number of elements per page","disabled":true,"key":"page_size","value":""},{"description":"Number of the page","disabled":true,"key":"page","value":""}],"raw":"{{base_url}}/api/v1/absence_types/:absence_type_id/pay_variants","variable":[{"description":"Sona unique identifier of the absence type","key":"absence_type_id","value":""}]}}},{"name":"Get a list of pay variants","request":{"description":"List all pay variants for the organisation","header":[],"method":"GET","url":{"host":["{{base_url}}"],"path":["api","v1","pay_variants"],"query":[{"description":"Number of elements per page","disabled":true,"key":"page_size","value":""},{"description":"Number of the page","disabled":true,"key":"page","value":""}],"raw":"{{base_url}}/api/v1/pay_variants","variable":[]}}},{"name":"Paginated list of pay variants","request":{"description":"List all pay variants associated with a shift type.","header":[],"method":"GET","url":{"host":["{{base_url}}"],"path":["api","v1","shift_types",":shift_type_id","pay_variants"],"query":[{"description":"Number of elements per page","disabled":true,"key":"page_size","value":""},{"description":"Number of the page","disabled":true,"key":"page","value":""}],"raw":"{{base_url}}/api/v1/shift_types/:shift_type_id/pay_variants","variable":[{"description":"Sona unique identifier of the shift type","key":"shift_type_id","value":""}]}}},{"name":"Creates a pay variant","request":{"body":{"mode":"raw","options":{"raw":{"language":"json"}},"raw":"{\n  \"counts_towards_annualised_hours\": true,\n  \"default\": false,\n  \"derives_annualised_hours_from_shifts\": false,\n  \"name\": \"Bank Holiday Premium\",\n  \"paid\": true,\n  \"subject_to_annualised_hours_bonus\": false\n}"},"description":"Creates a pay variant associated with a shift type.","header":[{"key":"Content-Type","value":"application/json"}],"method":"POST","url":{"host":["{{base_url}}"],"path":["api","v1","shift_types",":shift_type_id","pay_variants"],"query":[],"raw":"{{base_url}}/api/v1/shift_types/:shift_type_id/pay_variants","variable":[{"description":"Sona unique identifier of the shift type","key":"shift_type_id","value":""}]}}},{"name":"Gets a pay variant","request":{"description":"Gets a pay variant associated with a shift type.","header":[],"method":"GET","url":{"host":["{{base_url}}"],"path":["api","v1","shift_types",":shift_type_id","pay_variants",":pay_variant_id"],"query":[],"raw":"{{base_url}}/api/v1/shift_types/:shift_type_id/pay_variants/:pay_variant_id","variable":[{"description":"Sona unique identifier of the shift type","key":"shift_type_id","value":""},{"description":"Sona unique identifier of the pay variant","key":"pay_variant_id","value":""}]}}},{"name":"Updates a pay variant","request":{"body":{"mode":"raw","options":{"raw":{"language":"json"}},"raw":"{\n  \"counts_towards_annualised_hours\": true,\n  \"default\": false,\n  \"derives_annualised_hours_from_shifts\": false,\n  \"name\": \"Bank Holiday Premium\",\n  \"paid\": true,\n  \"subject_to_annualised_hours_bonus\": false\n}"},"description":"Updates a pay variant associated with a shift type.","header":[{"key":"Content-Type","value":"application/json"}],"method":"PUT","url":{"host":["{{base_url}}"],"path":["api","v1","shift_types",":shift_type_id","pay_variants",":pay_variant_id"],"query":[],"raw":"{{base_url}}/api/v1/shift_types/:shift_type_id/pay_variants/:pay_variant_id","variable":[{"description":"Sona unique identifier of the shift type","key":"shift_type_id","value":""},{"description":"Sona unique identifier of the pay variant","key":"pay_variant_id","value":""}]}}},{"name":"Deletes a pay variant","request":{"description":"Deletes a pay variant associated with a shift type.","header":[],"method":"DELETE","url":{"host":["{{base_url}}"],"path":["api","v1","shift_types",":shift_type_id","pay_variants",":pay_variant_id"],"query":[],"raw":"{{base_url}}/api/v1/shift_types/:shift_type_id/pay_variants/:pay_variant_id","variable":[{"description":"Sona unique identifier of the shift type","key":"shift_type_id","value":""},{"description":"Sona unique identifier of the pay variant","key":"pay_variant_id","value":""}]}}},{"name":"Links a pay variant to a shift type","request":{"description":"Links a pay variant to a shift type.","header":[],"method":"POST","url":{"host":["{{base_url}}"],"path":["api","v1","shift_types",":shift_type_id","pay_variants",":pay_variant_id","link"],"query":[],"raw":"{{base_url}}/api/v1/shift_types/:shift_type_id/pay_variants/:pay_variant_id/link","variable":[{"description":"Sona unique identifier of the shift type","key":"shift_type_id","value":""},{"description":"Sona unique identifier of the pay variant","key":"pay_variant_id","value":""}]}}},{"name":"Unlinks a pay variant from a shift type","request":{"description":"Unlinks a pay variant from a shift type.","header":[],"method":"DELETE","url":{"host":["{{base_url}}"],"path":["api","v1","shift_types",":shift_type_id","pay_variants",":pay_variant_id","link"],"query":[],"raw":"{{base_url}}/api/v1/shift_types/:shift_type_id/pay_variants/:pay_variant_id/link","variable":[{"description":"Sona unique identifier of the shift type","key":"shift_type_id","value":""},{"description":"Sona unique identifier of the pay variant","key":"pay_variant_id","value":""}]}}}],"name":"PayVariants"},{"description":null,"item":[{"name":"Get a list of people we support","request":{"description":"Get a list of people we support","header":[],"method":"GET","url":{"host":["{{base_url}}"],"path":["api","v1","people_we_support"],"query":[{"description":"Number of elements per page","disabled":true,"key":"page_size","value":""},{"description":"Number of the page","disabled":true,"key":"page","value":""},{"description":"Only people in this org unit (Sona id)","disabled":true,"key":"org_unit_id","value":""},{"description":"Exact match on the external id (`upload_id`)","disabled":true,"key":"upload_id","value":""},{"description":"Exact match on `integration_idx`","disabled":true,"key":"integration_idx","value":""},{"description":"Case-insensitive 'contains' match on name","disabled":true,"key":"name","value":""},{"description":"Current status: `active` or `inactive`. `active` includes people with no status record (`status: null`).","disabled":true,"key":"status","value":""},{"description":"Only people updated on or after this UTC datetime (ISO 8601, trailing Z). Only the person's own record is considered, not status or care package changes.","disabled":true,"key":"updated_at","value":""},{"description":"`asc` or `desc`, by name. When omitted the order is unspecified, as before.","disabled":true,"key":"order","value":""}],"raw":"{{base_url}}/api/v1/people_we_support","variable":[]}}},{"name":"Create person we support","request":{"body":{"mode":"raw","options":{"raw":{"language":"json"}},"raw":"{\n  \"end_date\": \"2025-01-15\",\n  \"integration_idx\": \"PWS-EXT-001\",\n  \"location\": {\n    \"address_line_1\": \"42 Elm Street\",\n    \"address_line_2\": \"Westbury\",\n    \"city\": \"Bristol\",\n    \"country\": \"United Kingdom\",\n    \"name\": \"Rosewood House\",\n    \"postcode\": \"BS1 4DJ\"\n  },\n  \"name\": \"Margaret Thompson\",\n  \"nhs_number\": \"943 476 5919\",\n  \"org_unit_id\": \"e27ad021-af0e-4ccf-95e8-1c7c84656c93\",\n  \"start_date\": \"2024-01-15\"\n}"},"description":"Create person we support","header":[{"key":"Content-Type","value":"application/json"}],"method":"POST","url":{"host":["{{base_url}}"],"path":["api","v1","people_we_support"],"query":[],"raw":"{{base_url}}/api/v1/people_we_support","variable":[]}}},{"name":"Get a person we support","request":{"description":"Get one person we support by Sona id, or by `upload_id` when `is_idx=true`. 404 if the person is not in your organisation.","header":[],"method":"GET","url":{"host":["{{base_url}}"],"path":["api","v1","people_we_support",":person_we_support_id"],"query":[{"description":"Set to true to look the person up by `upload_id`","disabled":true,"key":"is_idx","value":""}],"raw":"{{base_url}}/api/v1/people_we_support/:person_we_support_id","variable":[{"description":"Sona id, or `upload_id` when `is_idx=true`","key":"person_we_support_id","value":""}]}}},{"name":"Update person we support","request":{"body":{"mode":"raw","options":{"raw":{"language":"json"}},"raw":"{\n  \"end_date\": \"2025-06-30\",\n  \"integration_idx\": \"PWS-EXT-001\",\n  \"location\": {\n    \"address_line_1\": \"42 Elm Street\",\n    \"address_line_2\": \"Westbury\",\n    \"city\": \"Bristol\",\n    \"country\": \"United Kingdom\",\n    \"name\": \"Rosewood House\",\n    \"postcode\": \"BS1 4DJ\"\n  },\n  \"name\": \"Margaret Thompson\",\n  \"nhs_number\": \"943 476 5919\",\n  \"start_date\": \"2024-01-15\"\n}"},"description":"Update person we support, by Sona id or by `upload_id` when `is_idx=true`","header":[{"key":"Content-Type","value":"application/json"}],"method":"PUT","url":{"host":["{{base_url}}"],"path":["api","v1","people_we_support",":person_we_support_id"],"query":[{"description":"Set to true to look the person up by `upload_id`","disabled":true,"key":"is_idx","value":""}],"raw":"{{base_url}}/api/v1/people_we_support/:person_we_support_id","variable":[{"description":"Sona id, or `upload_id` when `is_idx=true`","key":"person_we_support_id","value":""}]}}},{"name":"List a person's status history","request":{"description":"When the person was active or inactive, and why, newest first. Read only. The current status is also on the person (`status`). Requires demand-based rostering to be enabled for your organisation (403 otherwise).","header":[],"method":"GET","url":{"host":["{{base_url}}"],"path":["api","v1","people_we_support",":person_we_support_id","status_records"],"query":[{"description":"Number of elements per page","disabled":true,"key":"page_size","value":""},{"description":"Number of the page","disabled":true,"key":"page","value":""},{"description":"Set to true to look the person up by `upload_id`","disabled":true,"key":"is_idx","value":""},{"description":"`active` or `inactive`","disabled":true,"key":"status","value":""},{"description":"Records that started on or after this date (YYYY-MM-DD, UTC)","disabled":true,"key":"from","value":""},{"description":"Records that started on or before this date (YYYY-MM-DD, UTC)","disabled":true,"key":"to","value":""},{"description":"Records created or changed on or after this time, YYYY-MM-DDThh:mm:ssZ in UTC (e.g. 2026-01-15T10:00:00Z)","disabled":true,"key":"updated_at","value":""}],"raw":"{{base_url}}/api/v1/people_we_support/:person_we_support_id/status_records","variable":[{"description":"Sona id, or `upload_id` when `is_idx=true`","key":"person_we_support_id","value":""}]}}},{"name":"List status records across your organisation","request":{"description":"Every person's status history, newest first, for keeping a copy in sync: pass `updated_at` to get only records created or changed since your last sync, including a record being ended by a newer one. Read only. Requires demand-based rostering to be enabled for your organisation (403 otherwise).","header":[],"method":"GET","url":{"host":["{{base_url}}"],"path":["api","v1","status_records"],"query":[{"description":"Number of elements per page","disabled":true,"key":"page_size","value":""},{"description":"Number of the page","disabled":true,"key":"page","value":""},{"description":"`active` or `inactive`","disabled":true,"key":"status","value":""},{"description":"Records that started on or after this date (YYYY-MM-DD, UTC)","disabled":true,"key":"from","value":""},{"description":"Records that started on or before this date (YYYY-MM-DD, UTC)","disabled":true,"key":"to","value":""},{"description":"Records created or changed on or after this time, YYYY-MM-DDThh:mm:ssZ in UTC (e.g. 2026-01-15T10:00:00Z)","disabled":true,"key":"updated_at","value":""}],"raw":"{{base_url}}/api/v1/status_records","variable":[]}}}],"name":"PeopleWeSupport"},{"description":null,"item":[{"name":"Get list of people we support budget entries","request":{"description":"Get list of people we support budget entries","header":[],"method":"GET","url":{"host":["{{base_url}}"],"path":["api","v1","people_we_support",":person_we_support_id","budgets"],"query":[{"description":"Number of elements per page","disabled":true,"key":"page_size","value":""},{"description":"Number of the page","disabled":true,"key":"page","value":""}],"raw":"{{base_url}}/api/v1/people_we_support/:person_we_support_id/budgets","variable":[{"description":"Sona unique identifier of the person we support","key":"person_we_support_id","value":""}]}}},{"name":"Create people we support budget entry","request":{"body":{"mode":"raw","options":{"raw":{"language":"json"}},"raw":"{\n  \"end_date\": \"2024-08-01\",\n  \"hours\": 10.0,\n  \"start_date\": \"2024-07-31\",\n  \"type_of_work_id\": \"b2b09422-c909-4198-a915-f66af3be2ec9\"\n}"},"description":"Create people we support budget entry","header":[{"key":"Content-Type","value":"application/json"}],"method":"POST","url":{"host":["{{base_url}}"],"path":["api","v1","people_we_support",":person_we_support_id","budgets"],"query":[],"raw":"{{base_url}}/api/v1/people_we_support/:person_we_support_id/budgets","variable":[{"description":"Sona unique identifier of the person we support","key":"person_we_support_id","value":""}]}}},{"name":"Update people we support budget entry","request":{"body":{"mode":"raw","options":{"raw":{"language":"json"}},"raw":"{\n  \"end_date\": \"2024-08-01\",\n  \"hours\": 10.0,\n  \"start_date\": \"2024-07-31\"\n}"},"description":"Update people we support budget entry","header":[{"key":"Content-Type","value":"application/json"}],"method":"PUT","url":{"host":["{{base_url}}"],"path":["api","v1","people_we_support",":person_we_support_id","budgets",":budget_id"],"query":[],"raw":"{{base_url}}/api/v1/people_we_support/:person_we_support_id/budgets/:budget_id","variable":[{"description":"Sona unique identifier of the person we support","key":"person_we_support_id","value":""},{"description":"Sona unique identifier of the budget entry","key":"budget_id","value":""}]}}}],"name":"PeopleWeSupportBudgets"},{"description":null,"item":[{"name":"Get a list of permission roles","request":{"description":"Permission Roles","header":[],"method":"GET","url":{"host":["{{base_url}}"],"path":["api","v1","permission_roles"],"query":[{"description":"Number of elements per page","disabled":true,"key":"page_size","value":""},{"description":"Number of the page","disabled":true,"key":"page","value":""}],"raw":"{{base_url}}/api/v1/permission_roles","variable":[]}}},{"name":"Update permission roles for an employment period","request":{"body":{"mode":"raw","options":{"raw":{"language":"json"}},"raw":"[\n  {\n    \"org_unit_ids\": [\n      \"\"\n    ],\n    \"permission_role_id\": \"\"\n  }\n]"},"description":"Update permission roles for an employment period based on employment_period_id OR the external idx","header":[{"key":"Content-Type","value":"application/json"}],"method":"PUT","url":{"host":["{{base_url}}"],"path":["api","v1","permission_roles","employment_periods",":employment_period_id_or_idx"],"query":[],"raw":"{{base_url}}/api/v1/permission_roles/employment_periods/:employment_period_id_or_idx","variable":[{"description":"Sona unique identifier of the employment period or external id","key":"employment_period_id_or_idx","value":""}]}}},{"name":"Add permission roles for an employment period","request":{"body":{"mode":"raw","options":{"raw":{"language":"json"}},"raw":"{\n  \"org_unit_ids\": [\n    \"a1b2c3d4-5678-4def-abcd-111111111111\",\n    \"d4e5f6a7-8901-4bcd-efab-333333333333\"\n  ]\n}"},"description":"Add permission roles for an employment period based on employment_period_id OR the external idx","header":[{"key":"Content-Type","value":"application/json"}],"method":"PUT","url":{"host":["{{base_url}}"],"path":["api","v1","permission_roles",":permission_role_id","employment_periods",":employment_period_id_or_idx"],"query":[],"raw":"{{base_url}}/api/v1/permission_roles/:permission_role_id/employment_periods/:employment_period_id_or_idx","variable":[{"description":"Sona unique identifier of the employment period or external id","key":"employment_period_id_or_idx","value":""},{"description":"Sona unique identifier of the permission role to add","key":"permission_role_id","value":""}]}}},{"name":"Remove permission roles for an employment period","request":{"description":"Remove permission roles for an employment period based on employment_period_id OR the external idx","header":[],"method":"DELETE","url":{"host":["{{base_url}}"],"path":["api","v1","permission_roles",":permission_role_id","employment_periods",":employment_period_id_or_idx"],"query":[],"raw":"{{base_url}}/api/v1/permission_roles/:permission_role_id/employment_periods/:employment_period_id_or_idx","variable":[{"description":"Sona unique identifier of the employment period or external id","key":"employment_period_id_or_idx","value":""},{"description":"Sona unique identifier of the permission role to remove","key":"permission_role_id","value":""}]}}},{"name":"Add org_unit to permission role for an employment period","request":{"description":"Add org_unit to permission role for an employment period based on employment_period_id OR the external idx","header":[],"method":"PUT","url":{"host":["{{base_url}}"],"path":["api","v1","permission_roles",":permission_role_id","employment_periods",":employment_period_id_or_idx","org_units",":org_unit_id"],"query":[],"raw":"{{base_url}}/api/v1/permission_roles/:permission_role_id/employment_periods/:employment_period_id_or_idx/org_units/:org_unit_id","variable":[{"description":"Sona unique identifier of the employment period or external id","key":"employment_period_id_or_idx","value":""},{"description":"Sona unique identifier of the permission role to add org unit to","key":"permission_role_id","value":""},{"description":"Sona unique identifier of the org unit to add to the permission role","key":"org_unit_id","value":""}]}}},{"name":"Remove org_unit from permission role for an employment period","request":{"description":"Remove org_unit from permission role for an employment period based on employment_period_id OR the external idx","header":[],"method":"DELETE","url":{"host":["{{base_url}}"],"path":["api","v1","permission_roles",":permission_role_id","employment_periods",":employment_period_id_or_idx","org_units",":org_unit_id"],"query":[],"raw":"{{base_url}}/api/v1/permission_roles/:permission_role_id/employment_periods/:employment_period_id_or_idx/org_units/:org_unit_id","variable":[{"description":"Sona unique identifier of the employment period or external id","key":"employment_period_id_or_idx","value":""},{"description":"Sona unique identifier of the permission role to update","key":"permission_role_id","value":""},{"description":"Sona unique identifier of the org unit to remove from the permission role","key":"org_unit_id","value":""}]}}}],"name":"PermissionRoles"},{"description":null,"item":[{"name":"Calculate productivity demand for an organisational unit","request":{"body":{"mode":"raw","options":{"raw":{"language":"json"}},"raw":"{\n  \"from_utc\": \"2024-06-15T06:00:00Z\",\n  \"interval_minutes\": 30,\n  \"roles\": [\n    {\n      \"id\": \"d3e4f5a6-7890-4abc-bcde-444444444444\",\n      \"name\": \"Registered Nurse\"\n    }\n  ],\n  \"rounding\": {\n    \"mode\": \"threshold\",\n    \"threshold\": 0.5\n  },\n  \"shifts\": [\n    {\n      \"end_datetime_utc\": \"2024-06-15T15:00:00Z\",\n      \"role_id\": \"d3e4f5a6-7890-4abc-bcde-444444444444\",\n      \"start_datetime_utc\": \"2024-06-15T07:00:00Z\"\n    }\n  ],\n  \"timezone\": \"Europe/London\",\n  \"to_utc\": \"2024-06-15T22:00:00Z\"\n}"},"description":"Runs the productivity engine calculator with the supplied shifts, rules, metrics, and roles.\nReturns staffing demand per role per time interval.\n\n**Metrics behaviour:**\n- If `metrics` is omitted, metric data is auto-loaded from the database using `metric_id` values\n  referenced in demand rules. The fallback order for metric values is: actual, then human forecasted,\n  then system forecasted.\n- If `metrics` is provided, the supplied data is used directly (useful for what-if scenarios).\n\n**Rounding behaviour:**\n- If `rounding` is omitted, raw float values are returned.\n- Supported modes: `none`, `ceil`, `floor`, `threshold`.\n- `threshold` mode requires a `threshold` value between 0 and 1.\n\n**Date range limit:** `to_utc - from_utc` must not exceed 7 days.\n","header":[{"key":"Content-Type","value":"application/json"}],"method":"POST","url":{"host":["{{base_url}}"],"path":["api","v1","org_units",":org_unit_id","productivity","calculate"],"query":[],"raw":"{{base_url}}/api/v1/org_units/:org_unit_id/productivity/calculate","variable":[{"description":"UUID of the organisational unit","key":"org_unit_id","value":""}]}}}],"name":"ProductivityCalculate"},{"description":null,"item":[{"name":"Gets the organisational unit productivity config","request":{"description":"Returns the productivity configuration for the organisational unit, including rule sets and rules. Returns null if no config exists.","header":[],"method":"GET","url":{"host":["{{base_url}}"],"path":["api","v1","org_units",":org_unit_id","productivity_config"],"query":[],"raw":"{{base_url}}/api/v1/org_units/:org_unit_id/productivity_config","variable":[{"description":"Sona unique identifier of the organisational unit","key":"org_unit_id","value":""}]}}}],"name":"ProductivityConfig"},{"description":null,"item":[{"name":"Get list of public holidays","request":{"description":"Get list of public holidays","header":[],"method":"GET","url":{"host":["{{base_url}}"],"path":["api","v1","public_holidays"],"query":[{"description":"Number of elements per page","disabled":true,"key":"page_size","value":""},{"description":"Number of the page","disabled":true,"key":"page","value":""}],"raw":"{{base_url}}/api/v1/public_holidays","variable":[]}}}],"name":"PublicHolidays"},{"description":null,"item":[{"name":"Get a list of rates of pay","request":{"description":"A rate of pay defines the monetary compensation for a specific user, type of work, and organisational unit over a date range. Rates can be hourly or salaried and are linked to an employment period. Use the query parameters to filter by user, type of work, org unit, or employment period.","header":[],"method":"GET","url":{"host":["{{base_url}}"],"path":["api","v1","rates_of_pay"],"query":[{"description":"Number of elements per page","disabled":true,"key":"page_size","value":""},{"description":"Number of the page","disabled":true,"key":"page","value":""},{"description":"The user_id to filter by","disabled":true,"key":"user_id","value":""},{"description":"The type_of_work_id to filter results by","disabled":true,"key":"type_of_work_id","value":""},{"description":"The org_unit_id to filter results by","disabled":true,"key":"org_unit_id","value":""},{"description":"The employment_period_id to filter results by","disabled":true,"key":"employment_period_id","value":""}],"raw":"{{base_url}}/api/v1/rates_of_pay","variable":[]}}},{"name":"Create a new rate of pay","request":{"body":{"mode":"raw","options":{"raw":{"language":"json"}},"raw":"{\n  \"amount\": 1750,\n  \"currency\": \"GBP\",\n  \"employment_period_id\": \"159600fb-3fa9-4687-bbc9-196375de6ee3\",\n  \"employment_period_idx\": \"159600fb-3fa9-4687-bbc9-196375de6ee3\",\n  \"finish_date\": \"2020-04-20\",\n  \"idx\": \"external id\",\n  \"is_default\": false,\n  \"label\": \"Standard Rate\",\n  \"org_unit_id\": \"c65bf5ec-5e82-4207-90cd-29caca7eae75\",\n  \"pay_type\": \"hourly\",\n  \"start_date\": \"2019-04-20\",\n  \"type_of_work_id\": \"159600fb-3fa9-4687-bbc9-196375de6ee3\"\n}"},"description":"Create a new rate of pay. See the RatesOfPay listing endpoint for a description of a rate of pay. One of the employment_period_id or employment_period_idx parameters is required. For organisations with UK minimum wage validation enabled, a GBP rate below the apprentice-rate hard floor (£7.55, £8.00 from April 2026) is rejected with a 422 naming the required amount on the rate field. This floor is not age-banded, so a rate that is legal for an apprentice but below the National Living Wage for the employee's age is still accepted. A salaried rate is compared on its hourly equivalent, derived from the contracted hours stored against the employment spec for the rate's start date; where none are stored the comparison is skipped. A currency that is not a recognised three-letter ISO 4217 code is also rejected with a 422.","header":[{"key":"Content-Type","value":"application/json"}],"method":"POST","url":{"host":["{{base_url}}"],"path":["api","v1","rates_of_pay"],"query":[],"raw":"{{base_url}}/api/v1/rates_of_pay","variable":[]}}},{"name":"Get an individual rate_of_pay","request":{"description":"Get an individual rate_of_pay. See the rate_of_pay listing endpoint for a description of rate_of_pay","header":[],"method":"GET","url":{"host":["{{base_url}}"],"path":["api","v1","rates_of_pay",":rate_of_pay_id_or_idx"],"query":[{"description":"If rate_of_pay_id_or_idx parameter is an external id this parameter should be set to true","disabled":true,"key":"is_idx","value":""}],"raw":"{{base_url}}/api/v1/rates_of_pay/:rate_of_pay_id_or_idx","variable":[{"description":"Sona unique identifier or external id of the rate of pay","key":"rate_of_pay_id_or_idx","value":""}]}}},{"name":"Update an existing rate of pay","request":{"body":{"mode":"raw","options":{"raw":{"language":"json"}},"raw":"{\n  \"amount\": 1750,\n  \"currency\": \"GBP\",\n  \"finish_date\": \"2020-04-20\",\n  \"idx\": \"new external id\",\n  \"is_default\": false,\n  \"is_idx\": true,\n  \"label\": \"Standard Rate\",\n  \"org_unit_id\": \"c65bf5ec-5e82-4207-90cd-29caca7eae75\",\n  \"pay_type\": \"hourly\",\n  \"start_date\": \"2019-04-20\",\n  \"type_of_work_id\": \"159600fb-3fa9-4687-bbc9-196375de6ee3\"\n}"},"description":"Update an existing rate of pay. See the RatesOfPay listing endpoint for a description of a rate of pay.  One of the id or idx parameters is required. To change the rate of pay's external identifier, send the new value as idx in the request body; rate_of_pay_id_or_idx in the path identifies the rate being updated. If both employment_period_id and employment_period_idx are given employment_period_id has a higher precedence. For organisations with UK minimum wage validation enabled, a GBP rate below the apprentice-rate hard floor (£7.55, £8.00 from April 2026) is rejected with a 422 naming the required amount on the rate field. This floor is not age-banded, so a rate that is legal for an apprentice but below the National Living Wage for the employee's age is still accepted. A salaried rate is compared on its hourly equivalent, derived from the contracted hours stored against the employment spec for the rate's start date; where none are stored the comparison is skipped. A currency that is not a recognised three-letter ISO 4217 code is also rejected with a 422.","header":[{"key":"Content-Type","value":"application/json"}],"method":"PUT","url":{"host":["{{base_url}}"],"path":["api","v1","rates_of_pay",":rate_of_pay_id_or_idx"],"query":[],"raw":"{{base_url}}/api/v1/rates_of_pay/:rate_of_pay_id_or_idx","variable":[{"description":"Sona unique identifier or external id of the rate of pay","key":"rate_of_pay_id_or_idx","value":""}]}}},{"name":"Delete a rate of pay","request":{"description":"Delete a rate of pay. This applies the same rules as deleting a rate in the Sona web client: the base (or default) rate of pay cannot be deleted, and a rate that is used by a shift or a payroll time to gross run cannot be deleted. Both are rejected with a 422 explaining why. A token restricted to specific endpoints must allow `DELETE /api/v1/rates_of_pay/:id`, otherwise the response is a 403.","header":[],"method":"DELETE","url":{"host":["{{base_url}}"],"path":["api","v1","rates_of_pay",":rate_of_pay_id_or_idx"],"query":[{"description":"IF rate_of_pay_id_or_idx is an external id, this parameter should be set to true","disabled":true,"key":"is_idx","value":""}],"raw":"{{base_url}}/api/v1/rates_of_pay/:rate_of_pay_id_or_idx","variable":[{"description":"Sona unique identifier or external id of the rate of pay","key":"rate_of_pay_id_or_idx","value":""}]}}}],"name":"RatesOfPay"},{"description":null,"item":[{"name":"Get a list of right to work documents","request":{"description":"List right to work documents for the current user","header":[],"method":"GET","url":{"host":["{{base_url}}"],"path":["api","v1","users",":user_id","standard_documents","right_to_work"],"query":[{"description":"Number of elements per page","disabled":true,"key":"page_size","value":""},{"description":"Number of the page","disabled":true,"key":"page","value":""}],"raw":"{{base_url}}/api/v1/users/:user_id/standard_documents/right_to_work","variable":[{"description":"The Sona unique identifier of the user.","key":"user_id","value":""}]}}},{"name":"Create a new right to work document","request":{"body":{"formdata":[{"description":"List of files to upload. The total upload size must not exceed 100 MB.","key":"file_uploads","type":"file","value":""},{"description":"The expiration date of the document","key":"expiry_date","type":"text","value":""},{"description":"The issue date of the document","key":"issue_date","type":"text","value":""},{"description":"The date when document was checked","key":"date_checked","type":"text","value":""},{"description":"The type of the document","key":"document_type","type":"text","value":""},{"description":"ISO 3166 Alpha-2 code for the country of issue of the document","key":"country_of_issue","type":"text","value":""},{"description":"ISO 3166 Alpha-2 code for the nationality in the document","key":"nationality","type":"text","value":""},{"description":"Share code","key":"share_code","type":"text","value":""},{"description":"COS field 1","key":"cos_field_1","type":"text","value":""},{"description":"COS field 2","key":"cos_field_2","type":"text","value":""},{"description":"Additional notes about document","key":"notes","type":"text","value":""}],"mode":"formdata"},"description":"Create a new right to work document entry","header":[],"method":"POST","url":{"host":["{{base_url}}"],"path":["api","v1","users",":user_id","standard_documents","right_to_work"],"query":[],"raw":"{{base_url}}/api/v1/users/:user_id/standard_documents/right_to_work","variable":[{"description":"The Sona unique identifier of the user.","key":"user_id","value":""}]}}},{"name":"Get a single right to work document.","request":{"description":"Get data about a single right to work document for a user.","header":[],"method":"GET","url":{"host":["{{base_url}}"],"path":["api","v1","users",":user_id","standard_documents","right_to_work",":id"],"query":[],"raw":"{{base_url}}/api/v1/users/:user_id/standard_documents/right_to_work/:id","variable":[{"description":"The Sona unique identifier of the right to work document.","key":"id","value":""},{"description":"The Sona unique identifier of the user.","key":"user_id","value":""}]}}},{"name":"Update a right to work document","request":{"body":{"formdata":[{"description":"List of files to upload. The total upload size must not exceed 20 MB. Will overwrite existing files.","key":"file_uploads","type":"file","value":""},{"description":"The expiration date of the document","key":"expiry_date","type":"text","value":""},{"description":"The issue date of the document","key":"issue_date","type":"text","value":""},{"description":"The date when document was checked","key":"date_checked","type":"text","value":""},{"description":"The type of the document","key":"document_type","type":"text","value":""},{"description":"ISO 3166 Alpha-2 code for the country of issue of the document","key":"country_of_issue","type":"text","value":""},{"description":"ISO 3166 Alpha-2 code for the nationality in the document","key":"nationality","type":"text","value":""},{"description":"Share code","key":"share_code","type":"text","value":""},{"description":"COS field 1","key":"cos_field_1","type":"text","value":""},{"description":"COS field 2","key":"cos_field_2","type":"text","value":""},{"description":"Additional notes about document","key":"notes","type":"text","value":""}],"mode":"formdata"},"description":"Update a right to work document entry","header":[],"method":"PUT","url":{"host":["{{base_url}}"],"path":["api","v1","users",":user_id","standard_documents","right_to_work",":id"],"query":[],"raw":"{{base_url}}/api/v1/users/:user_id/standard_documents/right_to_work/:id","variable":[{"description":"The Sona unique identifier of the user.","key":"user_id","value":""},{"description":"Sona unique identifier of the right to work document entry","key":"id","value":""}]}}},{"name":"Delete a right to work document entry","request":{"description":"Delete a right to work document entry.","header":[],"method":"DELETE","url":{"host":["{{base_url}}"],"path":["api","v1","users",":user_id","standard_documents","right_to_work",":id"],"query":[],"raw":"{{base_url}}/api/v1/users/:user_id/standard_documents/right_to_work/:id","variable":[{"description":"The Sona unique identifier of the user.","key":"user_id","value":""},{"description":"Sona unique identifier of the right to work document entry","key":"id","value":""}]}}}],"name":"RightToWorkDocuments"},{"description":null,"item":[{"name":"List services","request":{"description":"Org units with their demand-based rostering setup. Requires demand-based rostering to be enabled for your organisation (403 otherwise). `config` is the config in force today, or null. `updated_at` counts a change to the org unit, any of its configs or any of its demand periods, including a demand period being removed.","header":[],"method":"GET","url":{"host":["{{base_url}}"],"path":["api","v1","services"],"query":[{"description":"Number of elements per page","disabled":true,"key":"page_size","value":""},{"description":"Number of the page","disabled":true,"key":"page","value":""},{"description":"`true` only configured services, `false` only unconfigured","disabled":true,"key":"configured","value":""},{"description":"Case-insensitive 'contains' match on the service name","disabled":true,"key":"name","value":""},{"description":"Exact match on the service `idx` (the org unit `upload_id`)","disabled":true,"key":"idx","value":""},{"description":"Only services changed on or after this UTC datetime (ISO 8601, trailing Z)","disabled":true,"key":"updated_at","value":""}],"raw":"{{base_url}}/api/v1/services","variable":[]}}},{"name":"Get a service","request":{"description":"One service by Sona id, or by `idx` (its `upload_id`) when `is_idx=true`. 404 if it is not in your organisation.","header":[],"method":"GET","url":{"host":["{{base_url}}"],"path":["api","v1","services",":service_id"],"query":[{"description":"Set to true to look the service up by `idx`","disabled":true,"key":"is_idx","value":""}],"raw":"{{base_url}}/api/v1/services/:service_id","variable":[{"description":"Sona id, or `idx` when `is_idx=true`","key":"service_id","value":""}]}}},{"name":"Get a service's audit log","request":{"description":"Field-level changes to the service's capacity, target ratio and demand periods, newest first (entries made within the same second have no defined order). `actioned_by_source` is `api` for changes made through this API.","header":[],"method":"GET","url":{"host":["{{base_url}}"],"path":["api","v1","services",":service_id","audit_log"],"query":[{"description":"Number of elements per page","disabled":true,"key":"page_size","value":""},{"description":"Number of the page","disabled":true,"key":"page","value":""},{"description":"Set to true to look the service up by `idx`","disabled":true,"key":"is_idx","value":""}],"raw":"{{base_url}}/api/v1/services/:service_id/audit_log","variable":[{"description":"Sona id, or `idx` when `is_idx=true`","key":"service_id","value":""}]}}},{"name":"Create or update a service's config","request":{"body":{"mode":"raw","options":{"raw":{"language":"json"}},"raw":"{\n  \"inactive_reasons\": [\n    \"Hospital admission\",\n    \"Respite\"\n  ],\n  \"max_assignment_capacity\": 12,\n  \"start_date\": \"2026-01-01\"\n}"},"description":"Creates the config (201) when the service has no open-ended one, otherwise updates it in place (200) using **only the fields you send**, so other fields are never cleared. Send an explicit null to clear an optional field. `start_date` is required when creating. To end demand-based rostering for a service, set `end_date`; there is no delete. This never creates a service. Note: the config in force today is the one returned by GET; this endpoint acts on the open-ended config (no `end_date`), which can be a config that starts in the future. Simultaneous calls for one service are handled one after another, so only the first can create.","header":[{"key":"Content-Type","value":"application/json"}],"method":"PUT","url":{"host":["{{base_url}}"],"path":["api","v1","services",":service_id","config"],"query":[{"description":"Set to true to look the service up by `idx`","disabled":true,"key":"is_idx","value":""}],"raw":"{{base_url}}/api/v1/services/:service_id/config","variable":[{"description":"Sona id, or `idx` when `is_idx=true`","key":"service_id","value":""}]}}},{"name":"Replace a service's demand periods","request":{"body":{"mode":"raw","options":{"raw":{"language":"json"}},"raw":"{\n  \"demand_periods\": [\n    {\n      \"end_time\": \"19:00\",\n      \"id\": \"7a1f0c9e-2b3d-4c5e-8f60-1a2b3c4d5e6f\",\n      \"name\": \"Day\",\n      \"start_time\": \"07:00\"\n    },\n    {\n      \"end_time\": \"07:00\",\n      \"name\": \"Night\",\n      \"start_time\": \"19:00\"\n    }\n  ]\n}"},"description":"**This replaces the whole list.** Any existing demand period you leave out is deleted. To keep or change an existing period, send it with its `id`; an item without an `id` is created as a new period. Periods are never matched by name, and an `id` that is not one of this service's periods is a 422. Array order sets `position`. Overnight periods are fine (`start_time` after `end_time`). Sending the same list twice changes nothing. Demand period names are unique within a service, and periods are saved one at a time in list order, so a request that gives one period a name another period still holds (for example swapping two names) is refused with a 422. Do that in two requests. A period used by a care package hour line cannot be removed (409, with the period ids in `references`).","header":[{"key":"Content-Type","value":"application/json"}],"method":"PUT","url":{"host":["{{base_url}}"],"path":["api","v1","services",":service_id","demand_periods"],"query":[{"description":"Set to true to look the service up by `idx`","disabled":true,"key":"is_idx","value":""}],"raw":"{{base_url}}/api/v1/services/:service_id/demand_periods","variable":[{"description":"Sona id, or `idx` when `is_idx=true`","key":"service_id","value":""}]}}}],"name":"Services"},{"description":null,"item":[{"name":"Get a list of shifts","request":{"description":"A shift represents a method of accounting for a specific block of time. The most common usage is to represent a period of work to be performed. The vast majority of shifts created in the Sona platform are represented by the category `open_shifts`. The `shift_type` represents the sort of work being performed which is in turn linked to `type_of_work` which governs which users are able to see and work the shift. `min_start_datetime` and `max_start_datetime` are required and the longest timespan shifts can be listed for is 7 days.","header":[],"method":"GET","url":{"host":["{{base_url}}"],"path":["api","v1","shifts"],"query":[{"description":"Number of elements per page","disabled":true,"key":"page_size","value":""},{"description":"Number of the page","disabled":true,"key":"page","value":""},{"description":"Comma separated list of org unit IDs","disabled":true,"key":"org_unit_ids","value":""},{"description":"The earliest shift start date time to return in the following ISO 8601 UTC format: 2019-04-20T07:47:58Z (`YYYY-MM-DDTHH:mm:SSZ`)","disabled":false,"key":"min_start_datetime","value":""},{"description":"The latest shift start date time to return in the following ISO 8601 UTC format: 2019-04-20T07:47:58Z (`YYYY-MM-DDTHH:mm:SSZ`)","disabled":false,"key":"max_start_datetime","value":""},{"description":"The user_id to filter shifts by","disabled":true,"key":"user_id","value":""}],"raw":"{{base_url}}/api/v1/shifts?min_start_datetime=&max_start_datetime=","variable":[]}}},{"name":"Create a new shift","request":{"body":{"mode":"raw","options":{"raw":{"language":"json"}},"raw":"{\n  \"category\": \"open_shift\",\n  \"description\": \"Description of the shift\",\n  \"employment_period\": {\n    \"id\": \"3b1e8f02-6c4d-4f7a-9d51-2a8c0e7b4f19\"\n  },\n  \"finish_datetime\": \"2019-04-20T15:47:58Z\",\n  \"internal_id\": \"RGM15RMC\",\n  \"org_unit\": {\n    \"id\": \"9f8bda89-002a-45e0-8660-46e2fff714d2\"\n  },\n  \"shift_type\": {\n    \"id\": \"68f1a80c-3e72-4b7e-9542-c81b964600c7\"\n  },\n  \"start_datetime\": \"2019-04-20T07:47:58Z\",\n  \"user_working_shift\": {\n    \"id\": \"159600fb-3fa9-4687-bbc9-196375de6ee3\"\n  }\n}"},"description":"Create a new shift.\n\nWhen overlapping employment periods are enabled, a regular worker's shift belongs to one\nemployment period. Submit it as `employment_period.id` (find IDs with\n`GET /api/v1/employment_periods`). When it is omitted and exactly one of the worker's\nemployment periods covers the shift and holds the shift type's type of work, that one is\nstored. When several do, the request fails with an error on `employment_period_id`.\n","header":[{"key":"Content-Type","value":"application/json"}],"method":"POST","url":{"host":["{{base_url}}"],"path":["api","v1","shifts"],"query":[],"raw":"{{base_url}}/api/v1/shifts","variable":[]}}},{"name":"Get an individual shift","request":{"description":"Get an individual shift. See the shifts listing endpoint for more details on shifts.","header":[],"method":"GET","url":{"host":["{{base_url}}"],"path":["api","v1","shifts",":shift_id"],"query":[],"raw":"{{base_url}}/api/v1/shifts/:shift_id","variable":[{"description":"Sona unique identifier of the shift","key":"shift_id","value":""}]}}},{"name":"Update an individual shift","request":{"body":{"mode":"raw","options":{"raw":{"language":"json"}},"raw":"{\n  \"category\": \"open_shift\",\n  \"description\": \"Description of the shift\",\n  \"employment_period\": {\n    \"id\": \"3b1e8f02-6c4d-4f7a-9d51-2a8c0e7b4f19\"\n  },\n  \"finish_datetime\": \"2019-04-20T15:47:58Z\",\n  \"internal_id\": \"RGM15RMC\",\n  \"org_unit\": {\n    \"id\": \"9f8bda89-002a-45e0-8660-46e2fff714d2\"\n  },\n  \"shift_type\": {\n    \"id\": \"68f1a80c-3e72-4b7e-9542-c81b964600c7\"\n  },\n  \"start_datetime\": \"2019-04-20T07:47:58Z\",\n  \"user_working_shift\": {\n    \"id\": \"159600fb-3fa9-4687-bbc9-196375de6ee3\"\n  }\n}"},"description":"Update an individual shift.\n\nWhen overlapping employment periods are enabled, an update keeps the shift's employment\nperiod while it still covers the shift and holds the shift type's type of work. Otherwise,\nor when a shift without one changes its dates, worker or shift type, the employment period\nis resolved as on create: submit `employment_period.id` when several employment periods\ncould hold the shift. The employment period of a shift in a shift run cannot be changed\nthrough the API.\n","header":[{"key":"Content-Type","value":"application/json"}],"method":"PUT","url":{"host":["{{base_url}}"],"path":["api","v1","shifts",":shift_id"],"query":[],"raw":"{{base_url}}/api/v1/shifts/:shift_id","variable":[{"description":"Sona unique identifier of the shift","key":"shift_id","value":""}]}}},{"name":"Assign an individual shift to an agency","request":{"body":{"mode":"raw","options":{"raw":{"language":"json"}},"raw":"{\n  \"agency_id\": \"\",\n  \"agency_worker_first_name\": \"\",\n  \"agency_worker_id\": \"\",\n  \"agency_worker_last_name\": \"\"\n}"},"description":"Assign an individual shift to an agency. If none of `agency_worker_id`, `agency_worker_first_name` or `agency_worker_last_name` are provided (omitted, null or empty), the shift is assigned to the agency without a specific worker.","header":[{"key":"Content-Type","value":"application/json"}],"method":"PUT","url":{"host":["{{base_url}}"],"path":["api","v1","shifts",":shift_id","assign_to_agency"],"query":[],"raw":"{{base_url}}/api/v1/shifts/:shift_id/assign_to_agency","variable":[{"description":"Sona unique identifier of the shift","key":"shift_id","value":""}]}}},{"name":"Cancel an individual shift","request":{"description":"Cancel an individual shift","header":[],"method":"PUT","url":{"host":["{{base_url}}"],"path":["api","v1","shifts",":shift_id","cancel"],"query":[],"raw":"{{base_url}}/api/v1/shifts/:shift_id/cancel","variable":[{"description":"Sona unique identifier of the shift","key":"shift_id","value":""}]}}},{"name":"Unassign an individual shift from an agency","request":{"description":"Unassign an individual shift from an agency.","header":[],"method":"POST","url":{"host":["{{base_url}}"],"path":["api","v1","shifts",":shift_id","unassign_from_agency"],"query":[],"raw":"{{base_url}}/api/v1/shifts/:shift_id/unassign_from_agency","variable":[{"description":"Sona unique identifier of the shift","key":"shift_id","value":""}]}}}],"name":"Shifts"},{"description":null,"item":[{"name":"Get a list of Shift Types","request":{"description":"A shift type is an org unit specific definition of a type of work. It is link to a type of work which defines which users are qualified to claim or be assigned to the shift. Shift types can have default descriptions and start + finish times.","header":[],"method":"GET","url":{"host":["{{base_url}}"],"path":["api","v1","shift_types"],"query":[{"description":"Number of elements per page","disabled":true,"key":"page_size","value":""},{"description":"Number of the page","disabled":true,"key":"page","value":""},{"description":"The org unit to return shift types for","disabled":true,"key":"org_unit_id","value":""}],"raw":"{{base_url}}/api/v1/shift_types","variable":[]}}},{"name":"Create a Shift Type","request":{"body":{"mode":"raw","options":{"raw":{"language":"json"}},"raw":"{\n  \"color\": \"green\",\n  \"default_end_time\": \"21:50:00\",\n  \"default_shift_break_duration\": 100,\n  \"default_start_time\": \"07:50:00\",\n  \"description\": \"Shift description\",\n  \"is_absence\": true,\n  \"is_sleep\": true,\n  \"is_unpaid_absence_with_shifts\": true,\n  \"max_shift_length_minutes\": 720,\n  \"min_shift_length_minutes\": 480,\n  \"name\": \"An example shift type\",\n  \"night_shift\": true,\n  \"org_unit_id\": \"e27ad021-aa0e-4ccf-91e8-1c7c84656c93\",\n  \"peak_shift\": true,\n  \"shift_tags\": [\n    \"tag1\",\n    \"tag2\"\n  ],\n  \"staffing_model\": \"shared\",\n  \"type_of_work_id\": \"e27ad021-aa0e-4ccf-91e8-1c3c84626c91\"\n}"},"description":"Create a Shift Type","header":[{"key":"Content-Type","value":"application/json"}],"method":"POST","url":{"host":["{{base_url}}"],"path":["api","v1","shift_types"],"query":[],"raw":"{{base_url}}/api/v1/shift_types","variable":[]}}},{"name":"Get an individual shift type","request":{"description":"Get an individual shift type","header":[],"method":"GET","url":{"host":["{{base_url}}"],"path":["api","v1","shift_types",":shift_type_id"],"query":[],"raw":"{{base_url}}/api/v1/shift_types/:shift_type_id","variable":[{"description":"Sona unique identifier of the shift_type","key":"shift_type_id","value":""}]}}},{"name":"Update a Shift Type","request":{"body":{"mode":"raw","options":{"raw":{"language":"json"}},"raw":"{\n  \"color\": \"green\",\n  \"staffing_model\": \"shared\"\n}"},"description":"Update a Shift Type","header":[{"key":"Content-Type","value":"application/json"}],"method":"PUT","url":{"host":["{{base_url}}"],"path":["api","v1","shift_types",":shift_type_id"],"query":[],"raw":"{{base_url}}/api/v1/shift_types/:shift_type_id","variable":[{"description":"The Sona unique identifier of the shift type","key":"shift_type_id","value":""}]}}}],"name":"ShiftTypes"},{"description":null,"item":[{"name":"Get a list of skills and attributes","request":{"description":"Get a list of skills and attributes","header":[],"method":"GET","url":{"host":["{{base_url}}"],"path":["api","v1","skills_and_attributes"],"query":[{"description":"Number of elements per page","disabled":true,"key":"page_size","value":""},{"description":"Number of the page","disabled":true,"key":"page","value":""}],"raw":"{{base_url}}/api/v1/skills_and_attributes","variable":[]}}},{"name":"Create new skills and attributes","request":{"body":{"mode":"raw","options":{"raw":{"language":"json"}},"raw":"{\n  \"externally_managed\": false,\n  \"idx\": \"SKILL-MH-001\",\n  \"name\": \"Manual Handling\",\n  \"org_unit_ids\": [\n    \"fefc811b-f372-4472-9f28-31fb42add989\"\n  ],\n  \"organisation_id\": \"278612aa-4fb2-4697-bbc9-196375de6ef5\",\n  \"required_by_default\": true,\n  \"show_on_roster\": true,\n  \"show_on_shifts\": false,\n  \"type\": \"skill\"\n}"},"description":"Create new skills and attributes","header":[{"key":"Content-Type","value":"application/json"}],"method":"POST","url":{"host":["{{base_url}}"],"path":["api","v1","skills_and_attributes"],"query":[],"raw":"{{base_url}}/api/v1/skills_and_attributes","variable":[]}}},{"name":"Assigns a skill or an attribute to a user","request":{"body":{"mode":"raw","options":{"raw":{"language":"json"}},"raw":"{\n  \"end_date\": \"2025-06-30\",\n  \"start_date\": \"2025-01-01\",\n  \"user_id\": \"b9d1a3ad-a3db-4150-81c1-33c8c613271a\"\n}"},"description":"Use this endpoint to assign a skill or an attribute to a user. Skills can be given optional start and end dates.","header":[{"key":"Content-Type","value":"application/json"}],"method":"POST","url":{"host":["{{base_url}}"],"path":["api","v1","skills_and_attributes",":skill_attribute_id_or_idx","assign_to_user"],"query":[],"raw":"{{base_url}}/api/v1/skills_and_attributes/:skill_attribute_id_or_idx/assign_to_user","variable":[{"description":"A Sona unique identifier or an external unique identifier of the skill or attribute that is being assigned.","key":"skill_attribute_id_or_idx","value":""}]}}},{"name":"Take back assigned skill or attribute from the user","request":{"body":{"mode":"raw","options":{"raw":{"language":"json"}},"raw":"{\n  \"user_id\": \"b9d1a3ad-a3db-4150-81c1-33c8c613271a\"\n}"},"description":"Use this endpoint to remove a skill or an attribute from the user.","header":[{"key":"Content-Type","value":"application/json"}],"method":"POST","url":{"host":["{{base_url}}"],"path":["api","v1","skills_and_attributes",":skill_attribute_id_or_idx","retract"],"query":[],"raw":"{{base_url}}/api/v1/skills_and_attributes/:skill_attribute_id_or_idx/retract","variable":[{"description":"A Sona unique identifier or an external unique identifier of the skill or attribute that is being retracted.","key":"skill_attribute_id_or_idx","value":""}]}}},{"name":"Update an assigned skill or attribute for a user","request":{"body":{"mode":"raw","options":{"raw":{"language":"json"}},"raw":"{\n  \"end_date\": \"2025-06-30\",\n  \"start_date\": \"2025-01-01\",\n  \"user_id\": \"b9d1a3ad-a3db-4150-81c1-33c8c613271a\"\n}"},"description":"Use this endpoint to update the start date and/or end date of an existing skill or attribute assignment for a user.","header":[{"key":"Content-Type","value":"application/json"}],"method":"PUT","url":{"host":["{{base_url}}"],"path":["api","v1","skills_and_attributes",":skill_attribute_id_or_idx","update_assignment"],"query":[],"raw":"{{base_url}}/api/v1/skills_and_attributes/:skill_attribute_id_or_idx/update_assignment","variable":[{"description":"A Sona unique identifier or an external unique identifier of the skill or attribute.","key":"skill_attribute_id_or_idx","value":""}]}}}],"name":"SkillsAndAttributes"},{"description":null,"item":[{"name":"Get a list of Termination Reasons","request":{"description":"List the termination reasons configured for the organisation. These are the values accepted by the `termination_reason_id` field on the employment periods endpoints, so this endpoint is the source of truth for mapping a termination reason name to its Sona id.","header":[],"method":"GET","url":{"host":["{{base_url}}"],"path":["api","v1","termination_reasons"],"query":[{"description":"Number of elements per page","disabled":true,"key":"page_size","value":""},{"description":"Number of the page","disabled":true,"key":"page","value":""},{"description":"Filter by whether the termination reason is archived. If omitted, both archived and live termination reasons are returned.","disabled":true,"key":"archived","value":""}],"raw":"{{base_url}}/api/v1/termination_reasons","variable":[]}}},{"name":"Get an individual termination reason","request":{"description":"Get an individual termination reason. See the termination reason listing endpoint for a description of termination reasons.","header":[],"method":"GET","url":{"host":["{{base_url}}"],"path":["api","v1","termination_reasons",":termination_reason_id"],"query":[],"raw":"{{base_url}}/api/v1/termination_reasons/:termination_reason_id","variable":[{"description":"Sona unique identifier of the termination reason","key":"termination_reason_id","value":""}]}}}],"name":"TerminationReasons"},{"description":null,"item":[{"name":"Gets a organisational unit's time and attendance policy","request":{"description":"Returns the time and attendance policy of a organisational unit.","header":[],"method":"GET","url":{"host":["{{base_url}}"],"path":["api","v1","org_units",":org_unit_id","time_and_attendance_policy"],"query":[],"raw":"{{base_url}}/api/v1/org_units/:org_unit_id/time_and_attendance_policy","variable":[{"description":"Sona unique identifier of the organisational unit","key":"org_unit_id","value":""}]}}},{"name":"Creates an organisational unit's time and attendance policy","request":{"body":{"mode":"raw","options":{"raw":{"language":"json"}},"raw":"{\n  \"attendance_enforced_from\": \"2025-02-27T12:34:44.932935Z\",\n  \"clock_in_allowed_before_in_minutes\": 15,\n  \"clock_in_and_clock_out_required\": true,\n  \"clock_out_allowed_after_in_minutes\": 720,\n  \"clocking_requires_location_permission\": false,\n  \"early_clock_in_tolerance_in_minutes\": 0,\n  \"early_clock_out_tolerance_in_minutes\": 0,\n  \"geotag_required\": true,\n  \"geotag_required_for_shift_runs\": false,\n  \"late_clock_in_tolerance_in_minutes\": 0,\n  \"late_clock_out_tolerance_in_minutes\": 0,\n  \"location_tolerance_in_metres\": 500,\n  \"shift_break_attendance_enabled\": false,\n  \"time_and_attendance_required\": false,\n  \"unplanned_attendances_enabled\": false\n}"},"description":"Creates the time and attendance policy for an organisational unit.","header":[{"key":"Content-Type","value":"application/json"}],"method":"POST","url":{"host":["{{base_url}}"],"path":["api","v1","org_units",":org_unit_id","time_and_attendance_policy"],"query":[],"raw":"{{base_url}}/api/v1/org_units/:org_unit_id/time_and_attendance_policy","variable":[{"description":"Sona unique identifier of the organisational unit","key":"org_unit_id","value":""}]}}},{"name":"Updates an organisational unit's time and attendance policy","request":{"body":{"mode":"raw","options":{"raw":{"language":"json"}},"raw":"{\n  \"attendance_enforced_from\": \"2025-02-27T12:34:44.932935Z\",\n  \"clock_in_allowed_before_in_minutes\": 15,\n  \"clock_in_and_clock_out_required\": true,\n  \"clock_out_allowed_after_in_minutes\": 720,\n  \"clocking_requires_location_permission\": false,\n  \"early_clock_in_tolerance_in_minutes\": 0,\n  \"early_clock_out_tolerance_in_minutes\": 0,\n  \"geotag_required\": true,\n  \"geotag_required_for_shift_runs\": false,\n  \"late_clock_in_tolerance_in_minutes\": 0,\n  \"late_clock_out_tolerance_in_minutes\": 0,\n  \"location_tolerance_in_metres\": 500,\n  \"shift_break_attendance_enabled\": false,\n  \"time_and_attendance_required\": false,\n  \"unplanned_attendances_enabled\": false\n}"},"description":"Updates the time and attendance policy for an organisational unit.","header":[{"key":"Content-Type","value":"application/json"}],"method":"PUT","url":{"host":["{{base_url}}"],"path":["api","v1","org_units",":org_unit_id","time_and_attendance_policy"],"query":[],"raw":"{{base_url}}/api/v1/org_units/:org_unit_id/time_and_attendance_policy","variable":[{"description":"Sona unique identifier of the organisational unit","key":"org_unit_id","value":""}]}}},{"name":"Deletes an organisational unit's time and attendance policy","request":{"description":"Deletes the time and attendance policy for an organisational unit.","header":[],"method":"DELETE","url":{"host":["{{base_url}}"],"path":["api","v1","org_units",":org_unit_id","time_and_attendance_policy"],"query":[],"raw":"{{base_url}}/api/v1/org_units/:org_unit_id/time_and_attendance_policy","variable":[{"description":"Sona unique identifier of the organisational unit","key":"org_unit_id","value":""}]}}},{"name":"Gets a shift type's time and attendance policy","request":{"description":"Returns the time and attendance policy of a shift type.","header":[],"method":"GET","url":{"host":["{{base_url}}"],"path":["api","v1","shift_types",":shift_type_id","time_and_attendance_policy"],"query":[],"raw":"{{base_url}}/api/v1/shift_types/:shift_type_id/time_and_attendance_policy","variable":[{"description":"Sona unique identifier of the shift type","key":"shift_type_id","value":""}]}}},{"name":"Creates a shift type's time and attendance policy","request":{"body":{"mode":"raw","options":{"raw":{"language":"json"}},"raw":"{\n  \"attendance_enforced_from\": \"2025-02-27T12:34:44.932935Z\",\n  \"clock_in_allowed_before_in_minutes\": 15,\n  \"clock_in_and_clock_out_required\": true,\n  \"clock_out_allowed_after_in_minutes\": 720,\n  \"clocking_requires_location_permission\": false,\n  \"early_clock_in_tolerance_in_minutes\": 0,\n  \"early_clock_out_tolerance_in_minutes\": 0,\n  \"geotag_required\": true,\n  \"geotag_required_for_shift_runs\": false,\n  \"late_clock_in_tolerance_in_minutes\": 0,\n  \"late_clock_out_tolerance_in_minutes\": 0,\n  \"location_tolerance_in_metres\": 500,\n  \"shift_break_attendance_enabled\": false,\n  \"time_and_attendance_required\": false,\n  \"unplanned_attendances_enabled\": false\n}"},"description":"Creates the time and attendance policy for a shift type.","header":[{"key":"Content-Type","value":"application/json"}],"method":"POST","url":{"host":["{{base_url}}"],"path":["api","v1","shift_types",":shift_type_id","time_and_attendance_policy"],"query":[],"raw":"{{base_url}}/api/v1/shift_types/:shift_type_id/time_and_attendance_policy","variable":[{"description":"Sona unique identifier of the shift type","key":"shift_type_id","value":""}]}}},{"name":"Updates a shift type's time and attendance policy","request":{"body":{"mode":"raw","options":{"raw":{"language":"json"}},"raw":"{\n  \"attendance_enforced_from\": \"2025-02-27T12:34:44.932935Z\",\n  \"clock_in_allowed_before_in_minutes\": 15,\n  \"clock_in_and_clock_out_required\": true,\n  \"clock_out_allowed_after_in_minutes\": 720,\n  \"clocking_requires_location_permission\": false,\n  \"early_clock_in_tolerance_in_minutes\": 0,\n  \"early_clock_out_tolerance_in_minutes\": 0,\n  \"geotag_required\": true,\n  \"geotag_required_for_shift_runs\": false,\n  \"late_clock_in_tolerance_in_minutes\": 0,\n  \"late_clock_out_tolerance_in_minutes\": 0,\n  \"location_tolerance_in_metres\": 500,\n  \"shift_break_attendance_enabled\": false,\n  \"time_and_attendance_required\": false,\n  \"unplanned_attendances_enabled\": false\n}"},"description":"Updates the time and attendance policy for a shift type.","header":[{"key":"Content-Type","value":"application/json"}],"method":"PUT","url":{"host":["{{base_url}}"],"path":["api","v1","shift_types",":shift_type_id","time_and_attendance_policy"],"query":[],"raw":"{{base_url}}/api/v1/shift_types/:shift_type_id/time_and_attendance_policy","variable":[{"description":"Sona unique identifier of the shift type","key":"shift_type_id","value":""}]}}},{"name":"Deletes a shift type's time and attendance policy","request":{"description":"Deletes the time and attendance policy for a shift type.","header":[],"method":"DELETE","url":{"host":["{{base_url}}"],"path":["api","v1","shift_types",":shift_type_id","time_and_attendance_policy"],"query":[],"raw":"{{base_url}}/api/v1/shift_types/:shift_type_id/time_and_attendance_policy","variable":[{"description":"Sona unique identifier of the shift type","key":"shift_type_id","value":""}]}}}],"name":"TimeAndAttendancePolicy"},{"description":null,"item":[{"name":"Get a list of Training Course Attendances","request":{"description":"List all training course attendances for the current organisation.","header":[],"method":"GET","url":{"host":["{{base_url}}"],"path":["api","v1","training_course_attendances"],"query":[{"description":"Number of elements per page","disabled":true,"key":"page_size","value":""},{"description":"Number of the page","disabled":true,"key":"page","value":""},{"description":"The Sona unique identifier of the user","disabled":true,"key":"user_id","value":""},{"description":"The external id of the user","disabled":true,"key":"user_idx","value":""},{"description":"The Sona unique identifier of the training course","disabled":true,"key":"training_course_id","value":""},{"description":"The external id of the training course","disabled":true,"key":"training_course_idx","value":""}],"raw":"{{base_url}}/api/v1/training_course_attendances","variable":[]}}},{"name":"Create a new training course attendance","request":{"body":{"mode":"raw","options":{"raw":{"language":"json"}},"raw":"{\n  \"end_date\": \"2023-01-31\",\n  \"expiry_date\": \"2023-12-31\",\n  \"idx\": \"external-idx-123\",\n  \"start_date\": \"2023-01-01\",\n  \"training_course_id\": \"e27ad021-af0e-4ccf-95e8-1c7c84656c93\",\n  \"user_id\": \"e27ad021-af0e-4ccf-95e8-1c7c84656c93\"\n}"},"description":"Create a new training course attendance.","header":[{"key":"Content-Type","value":"application/json"}],"method":"POST","url":{"host":["{{base_url}}"],"path":["api","v1","training_course_attendances"],"query":[],"raw":"{{base_url}}/api/v1/training_course_attendances","variable":[]}}},{"name":"Get an individual training course attendance","request":{"description":"Get an individual training course attendance.","header":[],"method":"GET","url":{"host":["{{base_url}}"],"path":["api","v1","training_course_attendances",":attendance_id_or_idx"],"query":[],"raw":"{{base_url}}/api/v1/training_course_attendances/:attendance_id_or_idx","variable":[{"description":"The Sona unique identifier or external id of the training course attendance","key":"attendance_id_or_idx","value":""}]}}},{"name":"Update a training course attendance","request":{"body":{"mode":"raw","options":{"raw":{"language":"json"}},"raw":"{\n  \"end_date\": \"2023-01-31\",\n  \"expiry_date\": \"2023-12-31\",\n  \"start_date\": \"2023-01-01\"\n}"},"description":"Update a training course attendance.","header":[{"key":"Content-Type","value":"application/json"}],"method":"PUT","url":{"host":["{{base_url}}"],"path":["api","v1","training_course_attendances",":attendance_id_or_idx"],"query":[],"raw":"{{base_url}}/api/v1/training_course_attendances/:attendance_id_or_idx","variable":[{"description":"The Sona unique identifier or external id of the training course attendance","key":"attendance_id_or_idx","value":""}]}}},{"name":"Delete a training course attendance","request":{"description":"Delete a training course attendance.","header":[],"method":"DELETE","url":{"host":["{{base_url}}"],"path":["api","v1","training_course_attendances",":attendance_id_or_idx"],"query":[],"raw":"{{base_url}}/api/v1/training_course_attendances/:attendance_id_or_idx","variable":[{"description":"The Sona unique identifier or external id of the training course attendance","key":"attendance_id_or_idx","value":""}]}}}],"name":"TrainingCourseAttendances"},{"description":null,"item":[{"name":"Get a list of Training Courses","request":{"description":"List all training courses for the current organisation.","header":[],"method":"GET","url":{"host":["{{base_url}}"],"path":["api","v1","training_courses"],"query":[{"description":"Number of elements per page","disabled":true,"key":"page_size","value":""},{"description":"Number of the page","disabled":true,"key":"page","value":""},{"description":"Filter by whether courses are mandatory or not. If omitted all courses are returned.","disabled":true,"key":"mandatory","value":""},{"description":"Filter by course name. If omitted all courses are returned.","disabled":true,"key":"name","value":""},{"description":"Filter by course status (archived or live). If omitted all courses are returned.","disabled":true,"key":"archived","value":""}],"raw":"{{base_url}}/api/v1/training_courses","variable":[]}}},{"name":"Create a new training course","request":{"body":{"mode":"raw","options":{"raw":{"language":"json"}},"raw":"{\n  \"description\": \"In-depth guide to safety in the workplace\",\n  \"frequency\": \"annually\",\n  \"idx\": \"safety-training-101\",\n  \"mandatory\": \"true\",\n  \"name\": \"Safety Training\",\n  \"provider\": \"Safety Solutions Inc.\",\n  \"type\": \"online\"\n}"},"description":"Create a new training course.","header":[{"key":"Content-Type","value":"application/json"}],"method":"POST","url":{"host":["{{base_url}}"],"path":["api","v1","training_courses"],"query":[],"raw":"{{base_url}}/api/v1/training_courses","variable":[]}}},{"name":"Get an individual training course","request":{"description":"Get an individual training course.","header":[],"method":"GET","url":{"host":["{{base_url}}"],"path":["api","v1","training_courses",":course_id_or_idx"],"query":[],"raw":"{{base_url}}/api/v1/training_courses/:course_id_or_idx","variable":[{"description":"The Sona unique identifier or external id of the training course","key":"course_id_or_idx","value":""}]}}},{"name":"Update a training course","request":{"body":{"mode":"raw","options":{"raw":{"language":"json"}},"raw":"{\n  \"description\": \"Get up to date with the latest safety legislation\",\n  \"frequency\": \"annually\",\n  \"mandatory\": \"true\",\n  \"name\": \"Safety Trainiing\",\n  \"provider\": \"Safety Solutions Inc.\",\n  \"type\": \"online\"\n}"},"description":"Update a training course.","header":[{"key":"Content-Type","value":"application/json"}],"method":"PUT","url":{"host":["{{base_url}}"],"path":["api","v1","training_courses",":course_id_or_idx"],"query":[],"raw":"{{base_url}}/api/v1/training_courses/:course_id_or_idx","variable":[{"description":"Sona unique identifier or external id of the course to update","key":"course_id_or_idx","value":""}]}}},{"name":"Archive a training course","request":{"description":"Archive a training course.","header":[],"method":"PUT","url":{"host":["{{base_url}}"],"path":["api","v1","training_courses",":course_id_or_idx","archive"],"query":[],"raw":"{{base_url}}/api/v1/training_courses/:course_id_or_idx/archive","variable":[{"description":"Sona unique identifier or external id of the course to archive","key":"course_id_or_idx","value":""}]}}},{"name":"Turn an archived course back to live","request":{"description":"Unarchive a training course that was previously archived.","header":[],"method":"PUT","url":{"host":["{{base_url}}"],"path":["api","v1","training_courses",":course_id_or_idx","unarchive"],"query":[],"raw":"{{base_url}}/api/v1/training_courses/:course_id_or_idx/unarchive","variable":[{"description":"Sona unique identifier or external id of the course to unarchive","key":"course_id_or_idx","value":""}]}}}],"name":"TrainingCourses"},{"description":null,"item":[{"name":"Create a training venue","request":{"body":{"mode":"raw","options":{"raw":{"language":"json"}},"raw":"{\n  \"address_line_1\": \"1 Training Street\",\n  \"city\": \"Leeds\",\n  \"country_code\": \"GB\",\n  \"latitude\": 53.796,\n  \"longitude\": -1.547,\n  \"name\": \"Leeds Training Centre\",\n  \"parent_id\": \"e27ad021-aa0e-4ccf-91e8-1c7c84656c93\",\n  \"postcode\": \"LS1 4AP\",\n  \"timezone\": \"Europe/London\"\n}"},"description":"Creates a training venue: a rosterable org unit under the given parent with the organisation's 'Training venue' org unit type, its location (coordinates from latitude and longitude when given, else converted from a what3words reference when given, else derived from the postcode; sending both coordinates and a reference is refused), the organisation-wide 'Training' type of work (reused when one exists) and a 'Training' shift type at the venue linked to it. Everything is created in one transaction: an address that fails validation leaves nothing behind.","header":[{"key":"Content-Type","value":"application/json"}],"method":"POST","url":{"host":["{{base_url}}"],"path":["api","v1","training_venues"],"query":[],"raw":"{{base_url}}/api/v1/training_venues","variable":[]}}}],"name":"TrainingVenues"},{"description":null,"item":[{"name":"Get a list of Types Of Work","request":{"description":"A type of work defines a kind of work a user may be qualified to do or not. The users who can claim or be assigned to a shift are defined based on matching the type of work associated with the shift type to the types of work a user has associated with them","header":[],"method":"GET","url":{"host":["{{base_url}}"],"path":["api","v1","types_of_work"],"query":[{"description":"Number of elements per page","disabled":true,"key":"page_size","value":""},{"description":"Number of the page","disabled":true,"key":"page","value":""}],"raw":"{{base_url}}/api/v1/types_of_work","variable":[]}}},{"name":"Get an individual type of work","request":{"description":"Get an individual type of work","header":[],"method":"GET","url":{"host":["{{base_url}}"],"path":["api","v1","types_of_work",":type_of_work_id"],"query":[],"raw":"{{base_url}}/api/v1/types_of_work/:type_of_work_id","variable":[{"description":"Sona unique identifier of the type of work","key":"type_of_work_id","value":""}]}}}],"name":"TypesOfWork"},{"description":"Resolve a single user from an external identifier (National Insurance number, employee number, external employee id, or email) and return bundled related data. Additional endpoints in this group may be added over time.","item":[{"name":"Lookup user and periods","request":{"description":"Resolve **exactly one** user using **exactly one** of: `insurance_number`, `employee_number`, `external_id`, `contact_email`, `email`. Returns that user, their employment periods (up to 200), and `lookup.by`. HTTP status codes are documented under **Responses**.","header":[],"method":"GET","url":{"host":["{{base_url}}"],"path":["api","v1","users","lookup"],"query":[{"description":"UK NI number (case-insensitive). One of five identity params; use only one.","disabled":true,"key":"insurance_number","value":""},{"description":"Employment period employee number. One of five identity params; use only one.","disabled":true,"key":"employee_number","value":""},{"description":"Organisation user `external_employee_id`. One of five identity params; use only one.","disabled":true,"key":"external_id","value":""},{"description":"User contact email. One of five identity params; use only one.","disabled":true,"key":"contact_email","value":""},{"description":"Contact or work email. One of five identity params; use only one.","disabled":true,"key":"email","value":""}],"raw":"{{base_url}}/api/v1/users/lookup","variable":[]}}}],"name":"User lookup"},{"description":null,"item":[{"name":"Get a list of users","request":{"description":"A user in Sona typically represents an entity that can login to one or more components of the system. For example the manager portal or the mobile application. Additionally there are some headless users who cannot login, for example agency workers. Users by default have no access to anything and must be explicitly granted access to roles and organisational units.\n\n**Pagination**: Results are paginated. Use the `page` and `page_size` query parameters to navigate. The default page size is 10. Note: the parameter name is `page` (not `page_number`). The response includes `page_number`, `page_size`, `total_pages`, and `total_entries` metadata to assist with iteration. Example: `GET /api/v1/users?page=2&page_size=100`","header":[],"method":"GET","url":{"host":["{{base_url}}"],"path":["api","v1","users"],"query":[{"description":"Number of elements per page","disabled":true,"key":"page_size","value":""},{"description":"Number of the page","disabled":true,"key":"page","value":""},{"description":"The external id to filter by, useful for checking if a user with the given external id exists before deciding whether to create or update","disabled":true,"key":"external_id","value":""},{"description":"The employee number to filter by (often a payroll id)","disabled":true,"key":"employee_number","value":""},{"description":"The employee contact email to filter by","disabled":true,"key":"contact_email","value":""},{"description":"The employee email to filter by, returns a matching employee for either contact or work email","disabled":true,"key":"email","value":""},{"description":"The type of users to return (`agency` or `non_agency`), if omitted all users are returned","disabled":true,"key":"type","value":""},{"description":"The state of users to return (one of the values below), if omitted all users are returned","disabled":true,"key":"state","value":""},{"description":"Specify ordering with format 'field[direction]' where direction is 'asc' or 'desc' (e.g., 'updated_at[desc]'). If omitted, users are ordered by first_name, last_name for deterministic results","disabled":true,"key":"order","value":""},{"description":"Users who have their last day of employment on this date, if omitted the default order is returned","disabled":true,"key":"last_day_of_employment","value":""},{"description":"The insurance number to filter by","disabled":true,"key":"insurance_number","value":""},{"description":"Comma separated list of org unit identifiers (Sona internal identifiers or external identifiers). Only returns users with an administrative site relationship to the specified org units.","disabled":true,"key":"org_unit_ids","value":""},{"description":"UTC datetime to filter users updated on or after this timestamp. Use format YYYY-MM-DDThh:mm:ssZ in UTC (e.g. 2024-01-15T10:00:00Z).","disabled":true,"key":"updated_at","value":""}],"raw":"{{base_url}}/api/v1/users","variable":[]}}},{"name":"Create a new user","request":{"body":{"mode":"raw","options":{"raw":{"language":"json"}},"raw":"{\n  \"types_of_work\": [\n    {\n      \"id\": \"fefc811b-f372-4472-9f28-31fb42add989\"\n    }\n  ],\n  \"sex\": \"male\",\n  \"pay_group_ids\": [\n    \"2de697e7-29b6-498b-b324-00aa5de7c526\"\n  ],\n  \"contact_email\": \"jamie_watson_smith@example.com\",\n  \"insurance_number\": \"NI8682\",\n  \"home_address\": {\n    \"address_line_1\": \"24 Seddon Road\",\n    \"address_line_2\": \"Manchester\",\n    \"address_line_3\": \"\",\n    \"address_line_4\": \"\",\n    \"postcode\": \"MX1 2BR\"\n  },\n  \"base_roles\": [\n    {\n      \"name\": \"manager\"\n    }\n  ],\n  \"read_only_org_units\": [\n    {\n      \"id\": \"fefc811b-f372-4472-9f28-31fb42add989\"\n    }\n  ],\n  \"home_tier_org_units\": [\n    {\n      \"id\": \"fefc811b-f372-4472-9f28-31fb42add989\"\n    },\n    {\n      \"idx\": \"external_id\"\n    }\n  ],\n  \"next_of_kin\": [\n    {\n      \"first_name\": \"Sherlock\",\n      \"last_name\": \"Holmes\"\n    },\n    {\n      \"first_name\": \"Mary\",\n      \"last_name\": \"Morstan\",\n      \"relationship\": \"spouse\"\n    }\n  ],\n  \"work_phone_number\": \"07496756541\",\n  \"work_email\": \"jamie_watson_smith@example.com\",\n  \"exclude_from_payroll\": false,\n  \"identifies_as\": \"non_binary\",\n  \"receives_content_for_org_units\": [\n    {\n      \"id\": \"fefc811b-f372-4472-9f28-31fb42add989\"\n    }\n  ],\n  \"external_id\": \"123700\",\n  \"auth_strategies\": [\n    {\n      \"key\": \"user@example.org\",\n      \"type\": \"email\"\n    }\n  ],\n  \"date_of_birth\": \"01/02/1978\",\n  \"marital_status\": \"single\",\n  \"administrative_org_unit\": {\n    \"id\": \"fefc811b-f379-4472-9f28-31cb41add989\",\n    \"idx\": \"some external id\"\n  },\n  \"middle_name\": \"Watson\",\n  \"last_name\": \"Smith\",\n  \"bank_account\": {\n    \"account_name\": \"Personal\",\n    \"account_number\": \"12345678\",\n    \"bank_name\": \"Bank\",\n    \"country_code\": \"GB\",\n    \"sort_code\": \"12-34-56\"\n  },\n  \"manager_org_units\": [\n    {\n      \"id\": \"fefc811b-f379-4472-9f28-31cb41add989\"\n    },\n    {\n      \"id\": \"fefc811b-f379-4472-9f28-31fb42add989\"\n    }\n  ],\n  \"legal_first_name\": \"James\",\n  \"title\": \"dr\",\n  \"contact_phone_number\": \"07496756541\",\n  \"first_name\": \"James\",\n  \"appears_on_roster_for_org_units\": [\n    {\n      \"id\": \"fefc811b-f372-4472-9f28-31fb42add989\"\n    },\n    {\n      \"idx\": \"external_id\"\n    }\n  ],\n  \"blocked_for_org_units\": [\n    {\n      \"id\": \"4ba2cb25-2d7e-4658-95a6-1b6316a8cdd9\"\n    },\n    {\n      \"idx\": \"external_id\"\n    }\n  ],\n  \"assignable_org_units\": [\n    {\n      \"id\": \"fefc811b-f372-4472-9f28-31fb42add989\"\n    },\n    {\n      \"idx\": \"external_id\"\n    }\n  ],\n  \"preferred_name\": \"Jamie\",\n  \"contact_mobile_number\": \"07901234440\"\n}"},"description":"Create a new user. Some profile fields may become mandatory depending on your organisation's configuration. For example, `contact_email` is required when the `make_fields_mandatory` setting is enabled for your organisation.","header":[{"key":"Content-Type","value":"application/json"}],"method":"POST","url":{"host":["{{base_url}}"],"path":["api","v1","users"],"query":[],"raw":"{{base_url}}/api/v1/users","variable":[]}}},{"name":"Terminates an individual user's employment","request":{"body":{"mode":"raw","options":{"raw":{"language":"json"}},"raw":"{\n  \"final_date_of_employment\": \"2022-01-01\",\n  \"termination_reason_details\": \"User resigned\",\n  \"termination_reason_id\": \"fefc811b-f372-4472-9f28-31fb42add989\",\n  \"termination_would_rehire\": true\n}"},"description":"Terminate a user's employment. This is the correct endpoint for triggering the full termination workflow — simply setting `final_date_of_employment` via `PUT /users/{id}` will not change the user's state.\n\nAfter termination, the user's state is derived automatically based on `final_date_of_employment`: `leaver` if the date is today or in the future, `left` if in the past.\n\n**Organisations with the overlapping employment periods feature:** termination ends every contract running on `final_date_of_employment`. Each of those employment periods gets that date as its `finish_date` and the same termination fields. A contract that already ended before that date keeps its own `finish_date`. If any of the person's employment periods starts after `final_date_of_employment`, the termination is rejected and nothing changes. To end one contract while the others continue, set a `finish_date` on its current employment period with `PUT /api/v1/employment_periods/{employment_period_id}` instead.","header":[{"key":"Content-Type","value":"application/json"}],"method":"PUT","url":{"host":["{{base_url}}"],"path":["api","v1","users",":user_id_or_idx","terminate"],"query":[],"raw":"{{base_url}}/api/v1/users/:user_id_or_idx/terminate","variable":[{"description":"Sona unique identifier of the user or external id","key":"user_id_or_idx","value":""}]}}},{"name":"Undo termination of an individual user's employment","request":{"description":"Undo a previously processed termination, restoring the user to active status.","header":[],"method":"PUT","url":{"host":["{{base_url}}"],"path":["api","v1","users",":user_id_or_idx","undo_termination"],"query":[],"raw":"{{base_url}}/api/v1/users/:user_id_or_idx/undo_termination","variable":[{"description":"Sona unique identifier of the user or external id","key":"user_id_or_idx","value":""}]}}},{"name":"Get an individual user","request":{"description":"Get an individual user","header":[],"method":"GET","url":{"host":["{{base_url}}"],"path":["api","v1","users",":user_id"],"query":[],"raw":"{{base_url}}/api/v1/users/:user_id","variable":[{"description":"Sona unique identifier of the user","key":"user_id","value":""}]}}},{"name":"Update an individual user","request":{"body":{"mode":"raw","options":{"raw":{"language":"json"}},"raw":"{\n  \"administrative_org_unit\": {\n    \"id\": \"fefc811b-f379-4472-9f28-31cb41add989\",\n    \"idx\": \"some external ID\"\n  },\n  \"appears_on_roster_for_org_units\": [\n    {\n      \"id\": \"fefc811b-f372-4472-9f28-31fb42add989\"\n    }\n  ],\n  \"assignable_org_units\": [\n    {\n      \"id\": \"fefc811b-f372-4472-9f28-31fb42add989\"\n    }\n  ],\n  \"auth_strategies\": [\n    {\n      \"key\": \"user@example.org\",\n      \"type\": \"email\"\n    }\n  ],\n  \"bank_account\": {\n    \"account_name\": \"Personal\",\n    \"account_number\": \"12345678\",\n    \"bank_name\": \"Bank\",\n    \"country_code\": \"GB\",\n    \"sort_code\": \"12-34-56\"\n  },\n  \"base_roles\": [\n    {\n      \"name\": \"manager\"\n    }\n  ],\n  \"blocked_for_org_units\": [\n    {\n      \"id\": \"4ba2cb25-2d7e-4658-95a6-1b6316a8cdd9\"\n    }\n  ],\n  \"contact_email\": \"jamie_watson_smith@example.com\",\n  \"contact_mobile_number\": \"07901234440\",\n  \"contact_phone_number\": \"07496756541\",\n  \"date_of_birth\": \"01/02/1978\",\n  \"exclude_from_payroll\": false,\n  \"external_id\": \"123700\",\n  \"first_name\": \"James\",\n  \"home_address\": {\n    \"address_line_1\": \"24 Seddon Road\",\n    \"address_line_2\": \"Manchester\",\n    \"address_line_3\": \"\",\n    \"address_line_4\": \"\",\n    \"postcode\": \"MX1 2BR\"\n  },\n  \"home_tier_org_units\": [\n    {\n      \"id\": \"fefc811b-f372-4472-9f28-31fb42add989\"\n    }\n  ],\n  \"identifies_as\": \"non_binary\",\n  \"insurance_number\": \"NI8682\",\n  \"last_name\": \"Smith\",\n  \"legal_first_name\": \"James\",\n  \"manager_org_units\": [\n    {\n      \"id\": \"fefc811b-f379-4472-9f28-31cb41add989\",\n      \"to_remove\": true\n    },\n    {\n      \"id\": \"435a7e93-3d41-4de2-90af-d125357aa360\"\n    }\n  ],\n  \"marital_status\": \"single\",\n  \"middle_name\": \"Watson\",\n  \"next_of_kin\": [\n    {\n      \"id\": \"fefc811b-f379-4472-9f28-31cb41add989\",\n      \"to_remove\": true\n    },\n    {\n      \"first_name\": \"Sherlock\",\n      \"id\": \"fefc811b-f379-4472-9f28-31cb41add989\",\n      \"last_name\": \"Holmes\"\n    },\n    {\n      \"first_name\": \"Mary\",\n      \"last_name\": \"Morstan\",\n      \"relationship\": \"spouse\"\n    }\n  ],\n  \"preferred_name\": \"Jamie\",\n  \"read_only_org_units\": [\n    {\n      \"id\": \"fefc811b-f379-4472-9f28-31cb41add989\",\n      \"to_remove\": true\n    },\n    {\n      \"id\": \"435a7e93-3d41-4de2-90af-d125357aa360\"\n    }\n  ],\n  \"receives_content_for_org_units\": [\n    {\n      \"id\": \"fefc811b-f372-4472-9f28-31fb42add989\"\n    }\n  ],\n  \"sex\": \"male\",\n  \"title\": \"dr\",\n  \"types_of_work\": [\n    {\n      \"id\": \"fefc811b-f372-4472-9f28-31fb42add989\"\n    }\n  ],\n  \"work_email\": \"jamie_watson_smith@example.com\",\n  \"work_phone_number\": \"07496756541\"\n}"},"description":"Update an individual user","header":[{"key":"Content-Type","value":"application/json"}],"method":"PUT","url":{"host":["{{base_url}}"],"path":["api","v1","users",":user_id"],"query":[],"raw":"{{base_url}}/api/v1/users/:user_id","variable":[{"description":"Sona unique identifier of the user","key":"user_id","value":""}]}}},{"name":"Activate an individual user","request":{"description":"Activate an individual user","header":[],"method":"PUT","url":{"host":["{{base_url}}"],"path":["api","v1","users",":user_id","activate"],"query":[],"raw":"{{base_url}}/api/v1/users/:user_id/activate","variable":[{"description":"Sona unique identifier of the user","key":"user_id","value":""}]}}},{"name":"Deactivate an individual user","request":{"description":"Deactivate an individual user","header":[],"method":"PUT","url":{"host":["{{base_url}}"],"path":["api","v1","users",":user_id","deactivate"],"query":[],"raw":"{{base_url}}/api/v1/users/:user_id/deactivate","variable":[{"description":"Sona unique identifier of the user","key":"user_id","value":""}]}}}],"name":"Users"},{"description":null,"item":[{"name":"Get a list of subscriptions","request":{"description":"A Webhook Subscription allows API clients to get notified when an event occurs.","header":[],"method":"GET","url":{"host":["{{base_url}}"],"path":["api","v1","webhooks","subscriptions"],"query":[{"description":"Number of elements per page","disabled":true,"key":"page_size","value":""},{"description":"Number of the page","disabled":true,"key":"page","value":""}],"raw":"{{base_url}}/api/v1/webhooks/subscriptions","variable":[]}}},{"name":"Create a new subscription","request":{"body":{"mode":"raw","options":{"raw":{"language":"json"}},"raw":"{\n  \"event_type\": \"shift_updated\",\n  \"url\": \"https://example.com/api/v1/webhook_events\"\n}"},"description":"Create a new subscription for supplied event type","header":[{"key":"Content-Type","value":"application/json"}],"method":"POST","url":{"host":["{{base_url}}"],"path":["api","v1","webhooks","subscriptions"],"query":[],"raw":"{{base_url}}/api/v1/webhooks/subscriptions","variable":[]}}},{"name":"Delete a subscription","request":{"description":"Delete a webhook subscription by its ID","header":[],"method":"DELETE","url":{"host":["{{base_url}}"],"path":["api","v1","webhooks","subscriptions",":id"],"query":[],"raw":"{{base_url}}/api/v1/webhooks/subscriptions/:id","variable":[{"description":"The subscription ID","key":"id","value":""}]}}}],"name":"Webhook Subscriptions"},{"description":null,"item":[{"name":"Get a list of working preferences","request":{"description":"Returns a list of working preferences sorted by creation date. Allows filtering by `worker_id`.","header":[],"method":"GET","url":{"host":["{{base_url}}"],"path":["api","v1","working_preferences"],"query":[{"description":"Number of elements per page","disabled":true,"key":"page_size","value":""},{"description":"Number of the page","disabled":true,"key":"page","value":""},{"description":"The worker ID to filter by","disabled":true,"key":"worker_id","value":""}],"raw":"{{base_url}}/api/v1/working_preferences","variable":[]}}},{"name":"Create a working preference","request":{"body":{"mode":"raw","options":{"raw":{"language":"json"}},"raw":"{\n  \"days\": [\n    {\n      \"available\": true,\n      \"name\": \"monday\"\n    },\n    {\n      \"available\": false,\n      \"name\": \"tuesday\"\n    },\n    {\n      \"available\": true,\n      \"name\": \"wednesday\"\n    },\n    {\n      \"available\": true,\n      \"name\": \"thursday\"\n    },\n    {\n      \"available\": true,\n      \"name\": \"friday\"\n    },\n    {\n      \"available\": false,\n      \"name\": \"saturday\"\n    },\n    {\n      \"available\": false,\n      \"name\": \"sunday\"\n    }\n  ],\n  \"worker_id\": \"b9d1a3ad-a3db-4150-81c1-33c8c613271a\"\n}"},"description":"Creates a working preference","header":[{"key":"Content-Type","value":"application/json"}],"method":"POST","url":{"host":["{{base_url}}"],"path":["api","v1","working_preferences"],"query":[],"raw":"{{base_url}}/api/v1/working_preferences","variable":[]}}},{"name":"Update a working preference","request":{"body":{"mode":"raw","options":{"raw":{"language":"json"}},"raw":"{\n  \"days\": [\n    {\n      \"available\": true,\n      \"name\": \"monday\"\n    },\n    {\n      \"available\": false,\n      \"name\": \"tuesday\"\n    }\n  ]\n}"},"description":"Updates a working preference for the specified worker. The `worker_id` parameter should be the worker's user ID.","header":[{"key":"Content-Type","value":"application/json"}],"method":"PUT","url":{"host":["{{base_url}}"],"path":["api","v1","working_preferences",":worker_id"],"query":[],"raw":"{{base_url}}/api/v1/working_preferences/:worker_id","variable":[{"description":"The ID of the worker whose working preference to update","key":"worker_id","value":""}]}}},{"name":"Get a working preference by ID","request":{"description":"Returns a working preference by ID","header":[],"method":"GET","url":{"host":["{{base_url}}"],"path":["api","v1","working_preferences",":working_preference_id"],"query":[],"raw":"{{base_url}}/api/v1/working_preferences/:working_preference_id","variable":[{"description":"The ID of the working preference to get","key":"working_preference_id","value":""}]}}}],"name":"WorkingPreferences"},{"description":null,"item":[{"name":"Get a list of work restrictions","request":{"description":"Returns a list of work restrictions sorted by creation date. Allows filtering by `worker_id`.","header":[],"method":"GET","url":{"host":["{{base_url}}"],"path":["api","v1","work_restrictions"],"query":[{"description":"Number of elements per page","disabled":true,"key":"page_size","value":""},{"description":"Number of the page","disabled":true,"key":"page","value":""},{"description":"The worker ID to filter by","disabled":true,"key":"worker_id","value":""}],"raw":"{{base_url}}/api/v1/work_restrictions","variable":[]}}},{"name":"Create a work restriction","request":{"body":{"mode":"raw","options":{"raw":{"language":"json"}},"raw":"{\n  \"is_night_worker\": false,\n  \"is_under_ewtd\": true,\n  \"is_under_student_visa\": false,\n  \"worker_id\": \"b9d1a3ad-a3db-4150-81c1-33c8c613271a\"\n}"},"description":"Creates a work restriction for a worker","header":[{"key":"Content-Type","value":"application/json"}],"method":"POST","url":{"host":["{{base_url}}"],"path":["api","v1","work_restrictions"],"query":[],"raw":"{{base_url}}/api/v1/work_restrictions","variable":[]}}},{"name":"Get a work restriction by ID","request":{"description":"Returns a work restriction by ID","header":[],"method":"GET","url":{"host":["{{base_url}}"],"path":["api","v1","work_restrictions",":work_restriction_id"],"query":[],"raw":"{{base_url}}/api/v1/work_restrictions/:work_restriction_id","variable":[{"description":"The ID of the work restriction to get","key":"work_restriction_id","value":""}]}}},{"name":"Update a work restriction","request":{"body":{"mode":"raw","options":{"raw":{"language":"json"}},"raw":"{\n  \"is_night_worker\": false,\n  \"is_under_ewtd\": false,\n  \"is_under_student_visa\": true\n}"},"description":"Updates a work restriction for the specified worker. The `worker_id` parameter should be the worker's user ID.","header":[{"key":"Content-Type","value":"application/json"}],"method":"PUT","url":{"host":["{{base_url}}"],"path":["api","v1","work_restrictions",":worker_id"],"query":[],"raw":"{{base_url}}/api/v1/work_restrictions/:worker_id","variable":[{"description":"The ID of the worker whose work restriction to update","key":"worker_id","value":""}]}}}],"name":"WorkRestrictions"},{"description":null,"item":[{"name":"Get a user's Yapster migration info","request":{"body":{"mode":"raw","options":{"raw":{"language":"json"}},"raw":"{\n  \"yapster_confirmed_phones\": [\n    \"+447700900123\",\n    \"+447700900456\"\n  ]\n}"},"description":"Returns all the information required by the Yapster client to migrate a user from the Yapster app to the Sona app.","header":[{"key":"Content-Type","value":"application/json"}],"method":"POST","url":{"host":["{{base_url}}"],"path":["api","v1","yapster","users",":external_employee_id"],"query":[],"raw":"{{base_url}}/api/v1/yapster/users/:external_employee_id","variable":[{"description":"Customer employee ID","key":"external_employee_id","value":""}]}}}],"name":"YapsterMigration"},{"description":null,"item":[{"name":"Get user's holiday allowance for a year","request":{"description":"Get user's holiday allowance for a year","header":[],"method":"GET","url":{"host":["{{base_url}}"],"path":["api","v1","yearly_holiday_allowance"],"query":[{"description":"Sona unique identifier of the user to get the holiday allowance","disabled":false,"key":"user_id","value":""},{"description":"The start date holiday year for which to set the entitlement in the following ISO 8601 UTC format: 2019-04-20 (`YYYY-MM-DD`)","disabled":true,"key":"start_date","value":""},{"description":"The Sona unique identifier of the contract the request is about, from `contract_id` on `GET /api/v1/employment_periods`. Only used by organisations with overlapping employment periods enabled. Required when the user holds employment periods on several contracts covering the requested date; without it the only contract covering that date is used. A contract whose employment periods have ended still reads its own absence year covering the date.","disabled":true,"key":"contract_id","value":""}],"raw":"{{base_url}}/api/v1/yearly_holiday_allowance?user_id=","variable":[]}}},{"name":"Update a user's holiday allowance for a year","request":{"body":{"mode":"raw","options":{"raw":{"language":"json"}},"raw":"{\n  \"contract_id\": \"4f5c2a36-8f6e-4a0a-9d8e-2b1c7f3e6a51\",\n  \"start_date\": \"2019-04-20\",\n  \"user_id\": \"9f8bda89-002a-45e0-8660-46e2fff714d2\",\n  \"yearly_allowance\": 28\n}"},"description":"Update a user's holiday allowance for a year","header":[{"key":"Content-Type","value":"application/json"}],"method":"POST","url":{"host":["{{base_url}}"],"path":["api","v1","yearly_holiday_allowance"],"query":[],"raw":"{{base_url}}/api/v1/yearly_holiday_allowance","variable":[]}}}],"name":"YearlyHolidayAllowance"}],"variable":[{"key":"base_url","type":"string","value":"https://api.sona.is"},{"key":"api_token","type":"string","value":""}]}