POST /developer/v1/ingest/{source_type} accepts a batch of records from an
external system (an HRIS, payroll, or your own directory) and queues it for
asynchronous processing. One request carries records of one kind: legal
entities, departments, job titles, persons, or employees.
Use it to seed a tenant from another system and to keep it in sync afterwards.
Re-sending a record with the same external_id updates the object it created.
Request
Body:
A complete request that loads one person:
200:
ACCEPTED means the batch was stored and queued. Whether each record was
applied is known only after processing, see Results.
Who the key belongs to matters
The batch is applied on behalf of the key owner. Two consequences:- The key must be created by a super-administrator:
ingest:writeis available only to keys of users holding thePERMISSIONS:MANAGEpermission. - Reading the result back with
GET /employeesis bounded by the owner’s permission profile. Create the key as an administrator whose profile covers the entire company, otherwise the list will miss employees you just loaded, and an owner with no profile at all gets400 METADATA.FIELD_NOT_VISIBLE.
Load order
References between records are resolved byexternal_id, but not every object
can be referenced before it exists. Send batches in this order:
1
ORGANIZATIONS
Legal entities. Everything else references them.
2
DEPARTMENTS
A parent department may appear in the same batch or an earlier one.
3
JOB_TITLES
4
PERSONS
Persons must be loaded before employees. An employee whose
external_person_id is not loaded yet fails.5
EMPLOYEES
Links a person to a legal entity, department and job title.
ACCEPTED on the previous
request does not mean it has been applied. Placeholders make the order of
ORGANIZATIONS, DEPARTMENTS and JOB_TITLES forgiving, but send EMPLOYEES
only after the PERSONS batch has had time to apply (a few seconds per hundred
records), and re-send the employees that failed because their person was not
there yet.
Matching by external_id
Every record carries an external_id — the object’s identifier in your system.
The platform stores an external_id → internal id binding per source_type:
- a record with a known
external_idupdates the existing object; - a record with a new
external_idcreates an object only whencreate_missing: true, otherwise it is skipped; - references between records (
external_department_id,external_person_id, etc.) also use external identifiers — the platform resolves them itself.
The
external_id binding lives on the platform side and is not returned by
GET /employees: the Employee object has no external_id field and no filter
for it. To reconcile data after a load, keep the mapping on your side or rely on
natural keys (the employee_number, the IIN).Bindings are the only match key. A person or employee that already existed in
the tenant before the integration (created by hand or by another source) is not
matched by IIN or employee number: a record with a new
external_id tries to
create a second person with the same IIN and fails. Start the integration on a
tenant whose employees come only from this source, or agree the migration of
existing records with support.Record schemas
Fields outside the schema are ignored. Dates areYYYY-MM-DD strings. Empty
strings are treated as “not set”.
ORGANIZATIONS
DEPARTMENTS
JOB_TITLES
PERSONS
A person is the identity behind an employee. Loading a person creates or finds the platform account by IIN; theemail becomes the login of that account when
it has none yet.
Identity-document fields (passport number, issuing authority, registration
address, citizenship, gender) are not loaded through ingest today. Send them and
they are ignored; fill them in the app or wait for the schema to grow.
EMPLOYEES
1C · EMPLOYEES_FULL and DEPARTMENTS
Withsource_type = 1C the records follow the 1C export format — an employee
together with the person, fields in Russian: ТабельныйНомер, ДатаПриема,
Организация.Ссылка, Подразделение.Ссылка, Должность.Ссылка, and a nested
ФизЛицо object (Имя, Фамилия, Отчество, ИИН, Телефон, ДатаРождения).
1C · DEPARTMENTS carries Ссылка, Наименование, Родитель.Ссылка. Use the
generic KEDO schema for any other system.
Updates and terminations
Send the record again with the sameexternal_id and the new values. Always
send the complete record, not only the changed fields. To terminate an employee,
send the employee record with left_date: the employee becomes TERMINATED and
end_date is set.
Deleting objects through ingest is not supported.
Results
Processing is asynchronous. For each batch the platform keeps a processing log with four counters:
There is no endpoint yet that returns this log or per-record errors for an
ingest_request_id. Practical ways to confirm the result:
- Wait for processing: batches of hundreds of records take seconds.
- Re-read the data:
GET /employees?updated_since=…&expand=personreturns the created and updated employees,GET /employees/{id}a single one. - Subscribe to the
employee.changedwebhook — every changed profile arrives as an event.
Idempotency-Key.
Errors
Next steps
Employee sync
Full and incremental export back out.
Limits
Request rates and sizes.