Guides
Bulk import an HR feed
Bulk-import your institution's people and organizational units from a Classic HR feed (or a JSON groups batch).
Overview
POST /api/v0/imports/hr-feed/people
accepts an unmodified Classic hrmanifest
document (schema version 2.0) and treats it
as the authoritative active roster: people are created or updated, and (once a later run omits
them) deactivated. The feed carries 90 attributes; only the
12 below are ever read. Everything else is accepted and discarded at parse time — it is never
stored, logged, or reported on.
Imported fields
| Attribute | Element | Destination |
|---|---|---|
principalId |
record |
institutional ID |
principalName |
record |
username |
active |
record |
active |
affiliationType |
affiliation |
affiliation |
firstName |
name |
first name |
middleName |
name |
middle name |
lastName |
name |
last name |
prefix |
name |
prefix |
suffix |
name |
suffix |
title |
name |
title |
emailAddress |
email |
|
phoneNumber |
phone |
phone |
Which row is imported
A person can carry more than one <name>, <email>, or <phone>. At most one row per element is imported.
-
Name and email:
the first row in the document.
nameCode,emailType, and thedefaultandactiveflags are not imported and do not affect the choice, so put the row you want applied first. -
Phone:
the first row with
phoneType="WRK". The number is stored as the person's phone. A record whose only numbers areFAX,HM,MBL, orOTHleaves the phone unset — those numbers have no destination on the person record. - No qualifying row leaves the destination unset. It is never an error.
Limits
- 250 MB and 100,000 records per submission
- one roster import per institution at a time
- results are retained 90 days
Ignored fields
Every other Classic attribute is accepted but never stored, logged, or reported. This is enforced at the XML parser itself, not by later filtering.
| Attribute | Element |
|---|---|
statusEmailRecipient |
hrmanifest |
reportDate |
hrmanifest |
entityId |
record |
campus |
affiliation |
default |
affiliation |
active |
affiliation |
employeeStatus |
employment |
employeeType |
employment |
baseSalaryAmount |
employment |
primaryDepartment |
employment |
employeeId |
employment |
primaryEmployment |
employment |
addressTypeCode |
address |
addressLine1 |
address |
addressLine2 |
address |
addressLine3 |
address |
city |
address |
stateOrProvince |
address |
postalCode |
address |
country |
address |
default |
address |
active |
address |
nameCode |
name |
default |
name |
active |
name |
phoneType |
phone |
extension |
phone |
country |
phone |
default |
phone |
active |
phone |
emailType |
email |
default |
email |
active |
email |
citizenshipType |
kcExtendedAttributes |
county |
kcExtendedAttributes |
ageByFiscalYear |
kcExtendedAttributes |
race |
kcExtendedAttributes |
educationLevel |
kcExtendedAttributes |
degree |
kcExtendedAttributes |
major |
kcExtendedAttributes |
handicapped |
kcExtendedAttributes |
handicapType |
kcExtendedAttributes |
veteran |
kcExtendedAttributes |
veteranType |
kcExtendedAttributes |
visa |
kcExtendedAttributes |
visaType |
kcExtendedAttributes |
visaCode |
kcExtendedAttributes |
visaRenewalDate |
kcExtendedAttributes |
officeLocation |
kcExtendedAttributes |
secondaryOfficeLocation |
kcExtendedAttributes |
school |
kcExtendedAttributes |
yearGraduated |
kcExtendedAttributes |
directoryDepartment |
kcExtendedAttributes |
directoryTitle |
kcExtendedAttributes |
primaryTitle |
kcExtendedAttributes |
vacationAccrual |
kcExtendedAttributes |
onSabbatical |
kcExtendedAttributes |
idProvided |
kcExtendedAttributes |
idVerified |
kcExtendedAttributes |
multiCampusPrincipalId |
kcExtendedAttributes |
multiCampusPrincipalName |
kcExtendedAttributes |
salaryAnniversaryDate |
kcExtendedAttributes |
degreeCode |
degree |
degree |
degree |
graduationYear |
degree |
fieldOfStudy |
degree |
specialization |
degree |
school |
degree |
schoolId |
degree |
schoolIdCode |
degree |
unitNumber |
appointment |
jobCode |
appointment |
appointmentType |
appointment |
salary |
appointment |
startDate |
appointment |
endDate |
appointment |
jobTitle |
appointment |
preferedJobTitle |
appointment |
Run statuses
A run reports accepted, validating, applying, or
sweeping
while it is still working, and finishes in one of:
completed— every record applied and the sweep ran clean-
completed_with_failures— the run finished, but at least one record failed or a deactivation did -
completed_deactivations_withheld— applied, but the deactivation sweep exceeded its threshold and is waiting on your confirmation -
completed_deactivations_refused,completed_deactivations_stale— the sweep was refused outright, or the approved candidate set had drifted by the time you confirmed it -
failed— the run stopped and will not resume;failure.errorandfailure.messagesay why. How much applied depends on the cause: a rejected payload means nothing did, but a sweep failure happens only after every record already landed — the deactivation pass is what failed, not the roster -
failed_dependency_unavailable— attribute writes failed consecutively past the configured threshold, so the run halted instead of failing every remaining record one at a time. Withincounts.processed, records from chunks completed before the halt applied fully and resubmitting re-applies them as no-ops; the halting chunk's own failing records had their person data applied but not their attributes, so resubmitting re-attempts just those writes. The streak can come from either of two different causes — the destination page (or its reference data) being unreachable, or a value the destination keeps rejecting on every record — so check the run'sfailure.messageand the per-record results to see which one it was before resubmitting
Per-record failure reasons
GET /api/v0/imports/:runId/results
streams one outcome line per submitted record. Every line also carries attributes
— written, unchanged, skipped, or failed,
this record's own attribute-write outcome — and a warnings
list of field/value/reason
entries for this record's own attributes; a run-level warning is never on a per-record line, only
on the run itself. A failed record names one of:
-
missing_required_field— a required imported attribute was blank or absent invalid_value— a supplied value didn't match its required pattern-
duplicate_in_payload— the same institutional ID appeared twice in this submission -
held_by_other_person— the username is already assigned to a different person -
ambiguous_institutional_id— two existing people already hold this institutional ID -
identity_rejected— the record failed a save-time validation not listed above -
dependency_unavailable— the person was applied but their attribute write failed after retries -
section_create_rejected— the person's attribute section document could not be created -
validation_rejected— the attribute write failed a save-time field validation on the section document -
write_rejected— the attribute section document write failed for another reason -
unit_number_field_disabled,parent_not_found,parent_cycle— group-batch specific