Skip to main content

Request headers

string
required
The service user’s API token in the Bearer YOUR_TOKEN format. The school owner issues the token in the admin panel: Manage → School → For developers → API keys — see the “Authentication” section for details.
integer
required
The numeric ID of the seller — the account the school belongs to. Copy it on the API keys page, in the Integration data → Identifiers card. The token’s permissions are checked against this ID.
integer
required
The numeric ID of the school, found in the same place as Seller-Id. The value must match the seller’s school — otherwise a 400 error with cause: "ForbiddenSchoolMismatch" is returned.
An employment (employment) links a school user to a department and, optionally, a position. An employee can have several employment records in their history, but only one active record for a given department + position pair. You can omit the position — the employee is then listed in the department without a position, and an active record of this kind is unique per department + user pair. The record also stores the employment terms: kind (kind), type (type) and rate (rate).
All endpoints of the staff module are available only to schools in the Corporate segment. For other segments the request returns 401 with cause: "Forbidden" and the message Allowed only for Corporate school.
Transfer (transfer) and promotion (promote) do not modify the current record; they close it (finishAt, status Terminated) and create a new active record in the target department or with the new position. The employment terms (kind, type, rate) and the external identifier extId are carried over to the new record unchanged. The response contains the new employment record — with a new id. Therefore, store the employment’s extId in your system, not its id: the id changes with every transfer and promotion, the extId does not. A department manager assignment moves to the new record automatically; previously created absences remain linked to the closed record.
An employment can have an external identifier extId — the record’s ID in the client’s system (for example, an HR system). From 1 to 50 characters, without / or whitespace. It is unique within the school among open (not finished) employments: on transfer or promotion the extId moves to the new active record (the closed one keeps a copy), and after termination it is released — you can pass it again when rehiring. Separate routes ext/{extId}/transfer, ext/{extId}/promote and ext/{extId}/terminate work by extId; they only find an open record, so for an already closed employment they return StaffEmploymentNotFound.

Which operation to choose

The API has no employment deletion: a record is closed only through terminate and stays in the history. Every modifying operation comes in two variants: by employmentId in the request body and by extId in the path (ext/{extId}/...). They work the same way; the extId variant is more convenient for synchronization — you don’t need to store Exode’s internal IDs.

List employments

Requires authentication and the “Staff browsing” permission (StaffView).

Request parameters

Array parameters are passed by repeating the parameter in the query string: userIds=1&userIds=2&userIds=3.

Pagination

integer
Number of records to skip. Defaults to 0.
integer
Page number (an alternative to skip). Starts at 1.
integer
Number of records per page. Defaults to 100, maximum 1000.

Filtering

integer[]
Filter by employment IDs. Up to 250 values.
string[]
Filter by employment external identifiers (extId). Up to 250 values, each up to 50 characters.
integer[]
Filter by user IDs. Up to 250 values.
integer[]
Filter by department IDs. Up to 250 values.
string[]
Filter by department external identifiers (extId). Up to 250 values, each up to 50 characters.
integer[]
Filter by position IDs. Up to 250 values.
string[]
Filter by position external identifiers (extId). Up to 250 values, each up to 50 characters.
enum[]
Filter by employment status. Possible values: Active, Terminated. Up to 250 values.
boolean
If true, returns only employments that are in effect right now: status Active and a startAt date that has already passed. A hire with a future startAt is not included until that date — to get such records as well, use statuses=Active.
Search by employee: full name, login, user ID. Maximum 50 characters.

Sorting

enum
Sort direction by record creation date: ASC or DESC. The id and updatedAt parameters work the same way. Without sorting parameters, records of the same employee are listed together (grouped by userId).

Response fields

object
Paginated list of employments.

Hire an employee

Requires authentication and the “Staff Management” permission (StaffManage). Creates a new active employment record. The user, the department and the position (if specified) must belong to the school. The employee cannot have an active duplicate with the same department + position pair, and when hiring without a position — with the same department + user pair. If the user was previously terminated and has the Terminated status, hiring automatically restores their Active status. The department is required and is specified by ID or external identifier: pass exactly one parameter of the departmentId / departmentExtId pair. The position is optional: pass exactly one parameter of the positionId / positionExtId pair, or pass neither — the employee is then hired without a position. You cannot pass both fields of the same pair at once.

Request parameters

integer
required
ID of the user being hired. The user must already be registered in the school, otherwise UserNotBelongsToSchool is returned. The ID is returned when the user is created; you can find it by your external identifier with user/find. To create a user and hire them in a single call, use extra.staff.employments in user/create or user/upsert.
string
External identifier of the employment from the client’s system. From 1 to 50 characters, without / or whitespace. Must be unique within the school among open (not finished) employments.
integer
Position ID. The position must belong to the school. Optional: pass one parameter of the positionId / positionExtId pair, or pass neither — the employee is hired without a position.
string
External identifier (extId) of the position — an alternative to positionId.
integer
Department ID. The department must belong to the school. Pass exactly one parameter of the departmentId / departmentExtId pair.
string
External identifier (extId) of the department — an alternative to departmentId.
string
Employment start date in ISO 8601 format (for example, 2026-07-02T00:00:00.000Z). Defaults to the current moment. You can specify a past date (history migration) or a future date (a scheduled hire): a future record gets the Active status right away, but until startAt arrives it is not included in activeOnly=true results and cannot be assigned as a department manager.
enum
Employment kind: Main (main job), InternalSecondary (internal secondary job), ExternalSecondary (external secondary job). Defaults to Main.
enum
Employment type: FullTime (full-time) or PartTime (part-time). Defaults to FullTime.
number
Rate — a fraction of the full rate, from 0.01 to 1. Defaults to 1.

Transfer to another department

Requires authentication and the “Staff Management” permission (StaffManage). Closes the current active employment record (finishAt, status Terminated) and creates a new active record in the target department, keeping the position. The target department must belong to the school. If the employee already has an open record with the same position in the target department, StaffEmploymentAlreadyExists is returned.

Request parameters

integer
required
ID of the active employment record being transferred.
integer
ID of the target department. The department must belong to the school. Pass exactly one parameter of the toDepartmentId / toDepartmentExtId pair.
string
External identifier (extId) of the target department — an alternative to toDepartmentId.
string
Transfer date in ISO 8601 format. Must not be earlier than the current record’s startAt, otherwise StaffEmploymentInvalidTransitionDate is returned. Defaults to the current moment.

Transfer by external identifier

Requires authentication and the “Staff Management” permission (StaffManage). Same as transfer by employmentId, but the active employment record is looked up by the external identifier extId within the school. The request body is the same as for a regular transfer, without the employmentId field.

Request parameters

string
required
External identifier of the active employment record. The value in the path must be URL-encoded.
integer
ID of the target department. The department must belong to the school. Pass exactly one parameter of the toDepartmentId / toDepartmentExtId pair.
string
External identifier (extId) of the target department — an alternative to toDepartmentId.
string
Transfer date in ISO 8601 format. Must not be earlier than the current record’s startAt, otherwise StaffEmploymentInvalidTransitionDate is returned. Defaults to the current moment.

Change position

Requires authentication and the “Staff Management” permission (StaffManage). Closes the current active employment record (finishAt, status Terminated) and creates a new active record with the new position in the same department. The target position must belong to the school. If the employee already has an open record with the new position in this department, StaffEmploymentAlreadyExists is returned. The request must state the intent explicitly: pass a position (toPositionId or toPositionExtId) to assign it, or toPositionId: null to remove the position (the employee stays in the department without a position). If you pass none of these fields, the StaffEmploymentInputRequired error is returned.

Request parameters

integer
required
ID of the active employment record being changed.
integer | null
ID of the target position. The position must belong to the school. Pass exactly one parameter of the toPositionId / toPositionExtId pair. The value null removes the position — the employment stays in the department without a position. You cannot pass both fields of the pair at once.
string
External identifier (extId) of the target position — an alternative to toPositionId.
string
Position change date in ISO 8601 format. Must not be earlier than the current record’s startAt, otherwise StaffEmploymentInvalidTransitionDate is returned. Defaults to the current moment.

Change position by external identifier

Requires authentication and the “Staff Management” permission (StaffManage). Same as changing the position by employmentId, but the active employment record is looked up by the external identifier extId within the school. The request body is the same as for a regular position change, without the employmentId field: pass a position to assign it, or toPositionId: null to remove it; otherwise the StaffEmploymentInputRequired error is returned.

Request parameters

string
required
External identifier of the active employment record. The value in the path must be URL-encoded.
integer | null
ID of the target position. The position must belong to the school. Pass exactly one parameter of the toPositionId / toPositionExtId pair. The value null removes the position — the employment stays in the department without a position. You cannot pass both fields of the pair at once.
string
External identifier (extId) of the target position — an alternative to toPositionId.
string
Position change date in ISO 8601 format. Must not be earlier than the current record’s startAt, otherwise StaffEmploymentInvalidTransitionDate is returned. Defaults to the current moment.

Terminate an employee

Requires authentication and the “Staff Management” permission (StaffManage). Closes an active employment record: sets finishAt, changes the status to Terminated and removes the employee as manager of any departments. The response contains the closed record.
Terminating the last active employment automatically switches the user to the Terminated status — access to the platform is closed: sign-in is blocked and active sessions are ended. Rehiring (hire) a user with the Terminated status automatically restores their Active status.
Safeguards when terminating the last active employment: you cannot terminate yourself — the user on whose behalf the request is made (StaffCannotTerminateSelf) — or the school owner (StaffCannotTerminateSchoolOwner). Skip these users when reconciling the full employee list.
Termination takes effect at the moment of the call: the record gets the Terminated status immediately, and when terminating the last employment, access is closed immediately — even if finishAt is set in the future. There is no deferred termination, so call terminate on the actual termination day.

Request parameters

integer
required
ID of the active employment record being terminated.
string
Termination date in ISO 8601 format, stored in the record. Must not be earlier than the employment’s startAt, otherwise StaffEmploymentInvalidTransitionDate is returned. Defaults to the current moment.

Terminate by external identifier

Requires authentication and the “Staff Management” permission (StaffManage). Same as termination by employmentId, but the active employment record is looked up by the external identifier extId within the school. The request body is the same as for a regular termination, without the employmentId field. The same safeguards apply, as does the same logic of switching the user to the Terminated status when their last active employment is terminated.

Request parameters

string
required
External identifier of the active employment record. The value in the path must be URL-encoded.
string
Termination date in ISO 8601 format, stored in the record. Must not be earlier than the employment’s startAt, otherwise StaffEmploymentInvalidTransitionDate is returned. Defaults to the current moment.

Permission requirements

The staff module is available only to schools in the Corporate segment. Reading the list requires the “Staff browsing” permission (StaffView); hiring, transfer, promotion and termination require the “Staff Management” permission (StaffManage).
The service user must be authenticated with a token and have the appropriate access permissions for the specified school.

Updated: 2026-09-25 14:33 UTC