Upsert Employee
Looking for a step-by-step walkthrough of a specific job — create in Flaik only, create in the POS only, archive someone, make an instructor inactive in RTP? See Common Scenarios. This page is the field-by-field contract reference.
Overview
Creates or updates an employee in Flaik, and optionally propagates the same person data into the resort's POS as a POS Person, POS Employee, and/or POS Instructor record. A single request can target any combination of those four destinations using the actionUpsert* flags described below.
Processing is asynchronous and queued. The submit call returns a upsertEmployeeRequestId that you then poll via the Upsert Status endpoint until the request reaches a terminal state (CompletedSuccessfully or CompletedWithError). Optionally, supply a webHookUrl and Flaik will POST the result back to you when processing finishes.
1. POST /api/employee/upsert { … } → 200 { upsertEmployeeRequestId, addedToProcessingQueueUtc }
2. GET /api/employee/upsert/{upsertEmployeeRequestId} → poll until processingStatus is 3 or 4
3. (optional) Flaik POSTs the result to webHookUrl when processing completesAuthentication
Include your access token in the Authorization header:
Authorization: Bearer {access_token}This endpoint requires the flaik.connect.api.write scope. (Tokens carrying the legacy LegacyEnterpriseApiAdmin scope are also accepted for backwards compatibility, but new integrations should use flaik.connect.api.write.) See the Authentication Guide for details.
Submit Endpoint
POST {api-url}/api/employee/upsert
Content-Type: application/jsonWhat gets updated — the four action flags
The four actionUpsert* flags decide which downstream systems get touched. At least one must be true — a request with all four false is rejected with a 400.
Flag
When true
actionUpsertInFlaik
Creates or updates the Flaik employee record. Requires email, and requires primaryTeachingDisciplineId when creating (no id supplied).
actionUpsertPosPerson
Creates or updates the POS Person profile. Requires the upsertPosPerson block on the request. Uses top-level fields for everything except posGenderCode.
actionUpsertPosEmployee
Creates or updates the POS Employee record. Requires the upsertPosEmployee block.
actionUpsertPosInstructor
Creates or updates the POS Instructor profile. Requires the upsertPosInstructor block.
POS-side actions only have an effect for resorts with a POS integration enabled and the relevant subsystem configured.
Example Request — minimal Flaik-only upsert
The upsertEmployment block above is shown complete, which is a requirement rather than a style choice — see The employment block is all-or-nothing. The three wage position ids are sent as "" here because this employee has none; leaving the keys out is rejected.
Example Request — Flaik + POS Person + POS Instructor
Example Response (submit)
upsertEmployeeRequestId
integer
Identifier for this upsert request — pass to the Upsert Status endpoint to poll for the result
addedToProcessingQueueUtc
datetime
UTC timestamp the request was queued (YYYY-MM-DDTHH:mm:ss)
Validation Rules
The submit endpoint enforces the following rules. A 400/ProblemDetails is returned with the violated rule's message:
firstName is required
First Name is Required.
lastName is required
Last Name is Required.
dateOfBirth is required
Date Of Birth is Required.
email is required when actionUpsertInFlaik = true
Email required when ActionUpsertInFlaik set to true.
upsertPosPerson block is required when actionUpsertPosPerson = true
UpsertPosPerson required when ActionUpsertPosPerson set to true.
upsertPosEmployee block is required when actionUpsertPosEmployee = true
UpsertPosEmployee required when ActionUpsertPosEmployee set to true.
upsertPosInstructor block is required when actionUpsertPosInstructor = true
UpsertPosInstructor required when ActionUpsertPosInstructor set to true.
At least one actionUpsert* flag must be true
Nothing to process - at least one ActionUpsert* flag must be true.
upsertPosEmployee.posEmployeeId is required when actionUpsertPosEmployee = true
PosEmployeeId is required when ActionUpsertPosEmployee is set to true.
primaryTeachingDisciplineId is required when creating a Flaik employee (actionUpsertInFlaik = true and no id)
PrimaryTeachingDisciplineId is required when creating a flaik employee.
primaryTeachingDisciplineId, when supplied, must be between 1 and 65535
PrimaryTeachingDisciplineId must be between 1 and 65535.
status, when supplied, must be a valid employee status
Status must be a valid employee status (1=Active, 2=Archived, 3=Candidate).
upsertEmployment.startDate is required when upsertEmployment is supplied
StartDate is required when upsertEmployment is supplied - the employment block is full-replace, so every field must be sent.
upsertEmployment.jobTitleId is required when upsertEmployment is supplied
JobTitleId is required when upsertEmployment is supplied - the employment block is full-replace, so every field must be sent.
upsertEmployment.employmentTypeId is required when upsertEmployment is supplied
EmploymentTypeId is required when upsertEmployment is supplied - the employment block is full-replace, so every field must be sent.
upsertEmployment.wageTeachingPositionId is required when upsertEmployment is supplied
WageTeachingPositionId is required when upsertEmployment is supplied - send "" if the employee has none. Omitting it would clear the stored value.
upsertEmployment.wageNonTeachingPositionId is required when upsertEmployment is supplied
WageNonTeachingPositionId is required when upsertEmployment is supplied - send "" if the employee has none. Omitting it would clear the stored value.
upsertEmployment.wageTrainingPositionId is required when upsertEmployment is supplied
WageTrainingPositionId is required when upsertEmployment is supplied - send "" if the employee has none. Omitting it would clear the stored value.
Not validated here, but still enforced downstream: an RTP instructor must have a supervisor. That rule is POS-specific, so it is not checked when you submit — a missing supervisor surfaces as a per-destination error on the polling response (
actionUpsertPOSInstructorErrorMessage) rather than as a 400.
Request Body Field Reference
Identifiers
id
integer
No
Flaik employee identifier. Omit for new employees; include to update an existing one.
posIdentifier
string
No
POS person identifier (the resort's POS unique person id)
payrollIdentifier
string
No
Employee identifier in your payroll system
payrollSecondaryIdentifier
string
No
Secondary payroll identifier (e.g. a tax ID), if relevant
Person information
status
integer
No
1 Active Staff, 2 Archived (removed from staff management), 3 Candidate (talent pool). Defaults to Active on create. Send 2 to archive — see Common Scenarios.
firstName
string
Yes
Legal first name
middleName
string
No
Middle name. Forwarded to RTP if RTP integration is enabled. Not stored in Flaik directly.
lastName
string
Yes
Legal last name
preferredName
string
No
Preferred display name
dateOfBirth
date
Yes
YYYY-MM-DD
isSupervisor
boolean
No
Whether this employee is a supervisor. This is not who they report to.
supervisorFlaikEmployeeId
integer
No
Flaik employee id (employees.id) of this employee's supervisor. A Flaik identifier, not a POS or payroll id. The POS instructor's supervisor is a separate field — see upsertPosInstructor.posInstructorSupervisorUniqueIdentifier below.
genderName
string
No
Free-text gender identifier
genderPronoun
string
No
Preferred pronouns (e.g. "he/him")
Contact and address
email
string
when actionUpsertInFlaik
Primary email
phoneNumber
string
No
Primary phone
addressCountry
string
No
Country (free text)
addressState
string
No
State / province
addressStreetNumberAndName
string
No
Street line
addressCity
string
No
City
addressZip
string
No
ZIP / postal code
Passes
liftPassId
string
No
Lift pass identifier
mediaPassId
string
No
Media pass identifier
rfidPassId
string
No
RFID pass identifier
Teaching profile
primaryTeachingDisciplineId
integer
Yes, when creating a Flaik employee
The employee's primary teaching discipline, mirroring the Flaik UI. Non-teaching staff are not exempt — pass the Admin discipline id. Must be between 1 and 65535. Not required on update, so a partial update need not resend it. Flaik Connect does not currently expose a discipline reference list — obtain the valid ids for your resort (including the Admin discipline id) from your Flaik implementation contact.
teachingDisciplineIds
integer[]
No
Discipline IDs the instructor can teach
maxAbilityLevelIdAlpine
integer
No
Highest alpine level taught
maxAbilityLevelIdSnowboard
integer
No
Highest snowboard level taught
maxAbilityLevelIdTelemark
integer
No
Highest telemark level taught
maxAbilityLevelIdNordic
integer
No
Highest nordic level taught
maxAbilityLevelIdAdaptive
integer
No
Highest adaptive level taught
maxAbilityLevelIdAdaptiveSnowboard
integer
No
Highest adaptive snowboard level taught
Action flags
actionUpsertInFlaik
boolean
No (default false)
Upsert the Flaik employee record
actionUpsertPosPerson
boolean
No (default false)
Upsert the POS Person profile
actionUpsertPosEmployee
boolean
No (default false)
Upsert the POS Employee record
actionUpsertPosInstructor
boolean
No (default false)
Upsert the POS Instructor profile
Webhook
webHookUrl
string
No
If supplied, Flaik will POST the processing result to this URL when the request reaches a terminal state
upsertEmployment (optional block — but all-or-nothing when you send it)
Omitting this block entirely is fine and safe: the employee record is still created or updated, no error is raised, and the existing employment record is left completely untouched. If you are not changing someone's job title, dates or wages, leave it out.
What you must not do is send a partial block.
The employment block is all-or-nothing
Unlike the top-level employee fields, this block is full-replace: the employment record is rebuilt from exactly what you send, and anything you leave out is written as empty rather than carried over. To stop that happening silently, the API rejects an incomplete block with a 400.
Whenever upsertEmployment is present, all six of these are required:
startDate · jobTitleId · employmentTypeId · wageTeachingPositionId · wageNonTeachingPositionId · wageTrainingPositionId
Send "" for any wage position id the employee does not have — an empty string is a valid, explicit "none". It is the missing key that is rejected, not the empty value.
endDateis the exception, and it is not validated. It is optional by design, because employment can be open-ended. That means the API cannot tell "I leftendDateout" apart from "this employee has no end date" — so an omittedendDateclears any stored end date, with no error. If the employee has an end date you want to keep, send it on every request that includes this block.
The four wage rates are also not validated, because they are plain numbers and an omitted rate is indistinguishable from a genuine
0.0. OmittingteachingWageHourlywill set that wage to zero. Always send all four.
In short: treat upsertEmployment as a complete statement of the employee's employment, every time you send it. Partial blocks are either rejected or destructive.
jobTitleId
integer
Yes
Flaik job title identifier
employmentTypeId
integer
Yes
Employment type identifier
startDate
datetime
Yes
Employment start
endDate
datetime
No — but see below
Employment end. Nullable by design, so it is not validated — and omitting it clears any stored end date. Send it whenever the employee has one
teachingWageHourly
decimal
Not validated
Hourly wage for teaching activities. Omitting it sets the wage to 0.0
nonTeachingWageHourly
decimal
Not validated
Hourly wage for non-teaching activities. Omitting it sets the wage to 0.0
trainingWageHourly
decimal
Not validated
Hourly wage for training activities. Omitting it sets the wage to 0.0
privateRequestWageHourly
decimal
Not validated
Hourly wage for private-request activities. Omitting it sets the wage to 0.0
wageTeachingPositionId
string
Yes
External wage position identifier — teaching. Send "" if none
wageNonTeachingPositionId
string
Yes
External wage position identifier — non-teaching. Send "" if none
wageTrainingPositionId
string
Yes
External wage position identifier — training. Send "" if none
"Required" here means required when the block is present. The block itself remains optional — see above.
upsertPosPerson (required when actionUpsertPosPerson = true)
posGenderCode
string
POS-specific gender code. Override; everything else is taken from the top-level fields on the request.
Status vs Type — read this before setting any POS code
Four of the POS fields below pair up into two easily-confused sets. Sending a value to the wrong one does not error; it silently changes the wrong attribute. Getting this backwards has previously reclassified people's employment type while trying to deactivate them.
Concern
POS Employee
POS Instructor
Lifecycle — is this record active?
posEmployeeStatusCode
posProfileStatus
Type — what kind of employment?
posEmployeeTypeCode
posInstructorEmployeeTypeCode
For RTP, the lifecycle codes are 1 Active, 2 Inactive, 3 Changed, 4 Deleted, and the instructor employment types are 1 Full Time, 2 Part Time, 3 Casual. RTP names the underlying employment-type table "InstructorStatus", which is why posInstructorEmployeeTypeCode sounds like a status but is not one. Always source valid codes for your resort from GET api/ResortConfiguration/* rather than hard-coding them — the instructor employment types come from InstructorEmploymentTypes (field resortInstructorStatusCode).
upsertPosEmployee (required when actionUpsertPosEmployee = true)
posEmployeeId
string
Required when actionUpsertPosEmployee is true. The employee's payroll/HR identifier in the POS. A blank value is rejected with a 400.
posGovernmentId
string
Government ID stored in the POS
posEmployeeTypeCode
string
POS employee type code (not lifecycle)
posEmployeeDepartmentCode
string
POS department code
posEmployeeResortCode
string
POS resort code
posEmployeeStatusCode
string
POS employee lifecycle status code. RTP: 1 Active, 2 Inactive. Send 2 to make the POS employee inactive.
upsertPosInstructor (required when actionUpsertPosInstructor = true)
Prerequisite: POS Integration API 2.6.0 or later. Every field in this block behaves differently below 2.6.0 — employment type cannot be set on create, updates that omit it are rejected, and omitting rank or lesson location on a partial update silently overwrites them. The POS Integration API is installed per resort and does not update with Flaik Connect; check yours with
GET /health. See Common Scenarios › Prerequisites for the full table and the pre-2.6.0 workaround.
posInstructorSupervisorUniqueIdentifier
string
POS supervisor identifier. If omitted but supervisorEmployeeId is set on the top level, Flaik will fall back to that supervisor's POS unique identifier.
posInstructorLocationCode
string
Home location code
posInstructorLessonLocationCode
string
Default lesson location code
posInstructorPriorityRanking
string
Priority ranking for assignment
posInstructorEmployeeTypeCode
string
The instructor's employment type in the POS — RTP: 1 Full Time, 2 Part Time, 3 Casual. Valid values come from GET api/ResortConfiguration/InstructorEmploymentTypes (field resortInstructorStatusCode). Not a lifecycle status — see the Status vs Type note above. Omit on create and RTP defaults the instructor to Full Time. Omitting it on an update preserves the existing value (2.6.0+; see the prerequisite above).
posInstructorDisciplines
object
Map of discipline code → max ability level code. Overrides teachingDisciplineIds/maxAbilityLevelId* from the top level.
posProfileStatus
string
The instructor profile's lifecycle status — RTP: 1 Active, 2 Inactive, 3 Changed, 4 Deleted. Send 2 to make the instructor inactive. Numeric code, not a name: "Active" is not a valid value.
Webhook Callback
If webHookUrl is supplied on the request, Flaik will POST the same body returned by the Upsert Status endpoint to that URL once processing reaches CompletedSuccessfully or CompletedWithError. Webhook delivery is best-effort — for guaranteed observation of the result, also poll the status endpoint.
Error Responses
400
One of the validation rules above was violated
400
Request body is malformed JSON
401
Missing or invalid access token
403
Token does not include the flaik.connect.api.write scope
Need help with employee data ingest? Contact resortsupport@flaik.com.
Last updated
Was this helpful?
