> For the complete documentation index, see [llms.txt](https://knowledgebase.flaik.com/flaik-knowledge-base/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://knowledgebase.flaik.com/flaik-knowledge-base/for-it-specialists/3.-flaik-connect-api/employee-management/common-scenarios.md).

# Common Scenarios

### Prerequisites

**POS Integration API 2.6.0 or later is required for any scenario that writes a POS Instructor profile** — scenarios 2, 3, 4 and 7 on this page, and any use of the `upsertPosInstructor` block.

Check your resort's version with `GET /health` on the POS Integration API; it reports `Package Version`. The POS Integration API is installed per resort, so your version is independent of Flaik Connect and does not update with it. If you are below 2.6.0, contact <resortsupport@flaik.com> to arrange the upgrade before building against these flows.

On 2.5.x, POS Instructor writes behave differently in four ways — two of them silent:

| On 2.5.x                                                                 | Effect                                                                |
| ------------------------------------------------------------------------ | --------------------------------------------------------------------- |
| An instructor update that omits `posInstructorEmployeeTypeCode`          | Rejected with `InstructorEmployeeTypeCode: -1 not found`              |
| Setting `posInstructorEmployeeTypeCode` on create                        | Ignored — every instructor is created Full Time                       |
| A partial instructor update that omits `posInstructorPriorityRanking`    | **Silently overwrites the rank** with the default `9999`              |
| A partial instructor update that omits `posInstructorLessonLocationCode` | **Silently resets the lesson location** to the first configured entry |

The last two mean there is no safe *partial* instructor update below 2.6.0. If you must integrate before upgrading, always send the **complete** `upsertPosInstructor` block — including rank, lesson location, location and employment type — on every instructor write, and accept that employment type will not take effect on creates.

Scenarios 1, 5 and 6 do not write an instructor profile and are unaffected by this prerequisite.

### Before you start

**Everything on this page uses one endpoint.** `POST /api/employee/upsert` takes four independent action flags, and which combination you set is what makes a request "Flaik only", "POS only", "a deactivation", and so on. There is no separate create, update, delete or archive endpoint.

| You want to affect                              | Set                               |
| ----------------------------------------------- | --------------------------------- |
| The Flaik employee record                       | `actionUpsertInFlaik: true`       |
| The POS **Person** (the human)                  | `actionUpsertPosPerson: true`     |
| The POS **Employee** (their job)                | `actionUpsertPosEmployee: true`   |
| The POS **Instructor** (their teaching profile) | `actionUpsertPosInstructor: true` |

At least one must be `true`. Each destination succeeds or fails independently, so a partial result is normal and expected — always read the per-destination flags on the polling response rather than assuming all-or-nothing.

**Create vs update is decided by `id`.** Omit the top-level `id` and you create a new Flaik employee; supply it and you update that one. There is no separate update call.

**POS codes are resort-specific.** Every `pos*Code` value below is a code from the resort's POS reference data. Fetch the valid set from `GET api/ResortConfiguration/*` rather than hard-coding — the examples here use RTP's common values for illustration.

**Flaik ids are resort-specific too, and are not exposed by the API.** `primaryTeachingDisciplineId`, `jobTitleId` and `employmentTypeId` are Flaik reference ids that differ per resort. Flaik Connect has no endpoint that lists them, so obtain them from your Flaik implementation contact before you start. The numeric ids in the examples below are illustrative only.

**Processing is asynchronous.** Every submit returns an `upsertEmployeeRequestId` and queues the work. Poll [Upsert Status](https://knowledgebase.flaik.com/flaik-knowledge-base/for-it-specialists/3.-flaik-connect-api/employee-management/upsert-status) until `processingStatus` is `3` (CompletedSuccessfully) or `4` (CompletedWithError), or supply a `webHookUrl` and let Flaik call you back.

***

### 1. Create an employee in Flaik only

The common case for resorts without a POS integration, or when onboarding staff who will never appear in the POS.

Set only `actionUpsertInFlaik`. Remember that **`primaryTeachingDisciplineId` is required when creating** — including for non-teaching staff, who take the Admin discipline id. Omitting it returns a 400.

```json
{
  "firstName": "Sam",
  "lastName": "Smith",
  "dateOfBirth": "1990-06-22",
  "email": "sam.smith@example.com",
  "payrollIdentifier": "EMP123456",
  "primaryTeachingDisciplineId": 101,
  "actionUpsertInFlaik": true,
  "upsertEmployment": {
    "jobTitleId": 12,
    "employmentTypeId": 1,
    "startDate": "2024-11-15",
    "endDate": null,
    "teachingWageHourly": 30.0,
    "nonTeachingWageHourly": 25.0,
    "trainingWageHourly": 20.0,
    "privateRequestWageHourly": 0.0,
    "wageTeachingPositionId": "",
    "wageNonTeachingPositionId": "",
    "wageTrainingPositionId": ""
  }
}
```

**Confirm it landed:** poll the status endpoint and read `actionUpsertInFlaikEmployeeId` (the new Flaik employee id) and `actionUpsertInFlaikEmployeeWasCreated` (`true` for a create, `false` if it matched and updated an existing person).

> **The `upsertEmployment` block above is complete, and that is required.** If you send this block at all, it must carry `startDate`, `jobTitleId`, `employmentTypeId` and all three wage position ids — an incomplete block is rejected with a 400. Send `""` for wage position ids the employee does not have, as above. See scenario 4 for why.

> Omit `upsertEmployment` entirely and the employee is still created — but with no job title, employment dates or wage rates for the season. That is legal and safe; it is *partial* blocks that are not.

***

### 2. Create a person in the POS only

For staff who need to exist in the POS but not in Flaik's staff management — or when the POS is your system of record and Flaik is populated separately.

Leave `actionUpsertInFlaik` as `false` and enable the POS actions you need. Note that `posEmployeeId` is **required** whenever `actionUpsertPosEmployee` is `true`; a blank value is rejected with a 400 rather than failing later in the POS.

```json
{
  "firstName": "Alex",
  "lastName": "Jordan",
  "dateOfBirth": "1988-06-20",
  "email": "alex.jordan@example.com",
  "phoneNumber": "+1-555-0101",
  "actionUpsertInFlaik": false,
  "actionUpsertPosPerson": true,
  "actionUpsertPosEmployee": true,
  "actionUpsertPosInstructor": true,
  "upsertPosPerson": { "posGenderCode": "M" },
  "upsertPosEmployee": {
    "posEmployeeId": "EMP123456",
    "posEmployeeTypeCode": "1",
    "posEmployeeDepartmentCode": "10",
    "posEmployeeResortCode": "1",
    "posEmployeeStatusCode": "1"
  },
  "upsertPosInstructor": {
    "posInstructorSupervisorUniqueIdentifier": "1141500",
    "posInstructorLocationCode": "BL",
    "posInstructorLessonLocationCode": "BL",
    "posInstructorEmployeeTypeCode": "1",
    "posInstructorPriorityRanking": "1",
    "posInstructorDisciplines": { "1": "7" },
    "posProfileStatus": "1"
  }
}
```

**Confirm it landed:** read `actionUpsertPOSPersonIdentifier` (the POS person id — the RTP IPCode), plus the `*WasCreated` and `*HasError` flags for each POS destination.

> **An RTP instructor must have a supervisor.** This is enforced by the POS, not by request validation, so a missing supervisor comes back as an error on `actionUpsertPOSInstructorErrorMessage` rather than as a 400. If you omit `posInstructorSupervisorUniqueIdentifier` but set the top-level `supervisorFlaikEmployeeId`, Flaik falls back to that supervisor's POS identifier.

> **Creating an instructor without `posInstructorEmployeeTypeCode` makes them Full Time**, because that is RTP's default. Set it explicitly if they are Part Time or Casual using the correct codes for your resort.

***

### 3. Create an employee in both Flaik and the POS

The standard onboarding path for an integrated resort: one call creates the Flaik employee and mirrors the person into the POS.

Combine scenarios 1 and 2 — enable `actionUpsertInFlaik` alongside the POS flags. The top-level person fields (name, date of birth, contact details, address) are shared: the POS Person is built from them, and `upsertPosPerson` only carries POS-specific overrides such as `posGenderCode`.

```json
{
  "firstName": "Sam",
  "lastName": "Smith",
  "dateOfBirth": "1990-06-22",
  "email": "sam.smith@example.com",
  "payrollIdentifier": "EMP123456",
  "primaryTeachingDisciplineId": 101,
  "teachingDisciplineIds": [1, 2],
  "actionUpsertInFlaik": true,
  "actionUpsertPosPerson": true,
  "actionUpsertPosEmployee": true,
  "actionUpsertPosInstructor": true,
  "upsertEmployment": {
    "jobTitleId": 12,
    "employmentTypeId": 1,
    "startDate": "2024-11-15",
    "endDate": "2025-04-30",
    "teachingWageHourly": 30.0,
    "nonTeachingWageHourly": 25.0,
    "trainingWageHourly": 20.0,
    "privateRequestWageHourly": 0.0,
    "wageTeachingPositionId": "WT-4471",
    "wageNonTeachingPositionId": "WN-4471",
    "wageTrainingPositionId": "WR-4471"
  },
  "upsertPosPerson": { "posGenderCode": "M" },
  "upsertPosEmployee": {
    "posEmployeeId": "EMP123456",
    "posEmployeeTypeCode": "1",
    "posEmployeeDepartmentCode": "10",
    "posEmployeeResortCode": "1",
    "posEmployeeStatusCode": "1"
  },
  "upsertPosInstructor": {
    "posInstructorSupervisorUniqueIdentifier": "1141500",
    "posInstructorLocationCode": "BL",
    "posInstructorLessonLocationCode": "BL",
    "posInstructorEmployeeTypeCode": "1",
    "posInstructorPriorityRanking": "1",
    "posInstructorDisciplines": { "1": "7" },
    "posProfileStatus": "1"
  }
}
```

**Confirm it landed:** you should get both `actionUpsertInFlaikEmployeeId` and `actionUpsertPOSPersonIdentifier` back. Store both — the Flaik id and the POS identifier are the keys you will use for later updates.

> **Partial success is real.** The Flaik write can succeed while a POS write fails. When retrying, re-submit with **only the failed actions enabled** rather than replaying the whole payload.

***

### 4. Update an existing profile

Updating uses the same endpoint. Two rules govern what happens:

* **Supply the top-level `id`** (the Flaik employee id) to target an existing person. For POS-only updates, supply `posIdentifier` so Flaik knows which POS person to update.
* **Enable only the actions you want to touch.** Leaving `actionUpsertPosInstructor` as `false` means the instructor profile is not written at all — this is how you scope an update.

#### Update the Flaik record only

```json
{
  "id": 15,
  "firstName": "Sam",
  "lastName": "Smith",
  "dateOfBirth": "1990-06-22",
  "email": "sam.newemail@example.com",
  "phoneNumber": "+1-555-0199",
  "actionUpsertInFlaik": true
}
```

`primaryTeachingDisciplineId` is not required on update, so a partial update need not resend it.

#### The one exception: `upsertEmployment` is all-or-nothing

Everything above describes the **employee** fields, which preserve what you omit. The `upsertEmployment` block does not work that way, and it is the one place where a partial update is unsafe.

That block is **full-replace**: the employment record is rebuilt from exactly what you send. To stop fields disappearing silently, the API rejects an incomplete block with a **400**. When `upsertEmployment` is present it must carry:

`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", and only the missing key is rejected.

**So there is no such thing as a partial employment update.** To change one wage rate, re-send the whole block with that one value different:

```json
{
  "id": 15,
  "firstName": "Sam",
  "lastName": "Smith",
  "dateOfBirth": "1990-06-22",
  "email": "sam.smith@example.com",
  "actionUpsertInFlaik": true,
  "upsertEmployment": {
    "jobTitleId": 12,
    "employmentTypeId": 1,
    "startDate": "2024-11-15",
    "endDate": "2025-04-30",
    "teachingWageHourly": 34.50,
    "nonTeachingWageHourly": 25.0,
    "trainingWageHourly": 20.0,
    "privateRequestWageHourly": 0.0,
    "wageTeachingPositionId": "WT-4471",
    "wageNonTeachingPositionId": "WN-4471",
    "wageTrainingPositionId": "WR-4471"
  }
}
```

**If you are not changing employment at all, leave the block out entirely** — that is safe and leaves the existing employment record untouched.

> **Two fields in this block are not covered by the 400, so they need your care.** `endDate` is optional by design, so the API cannot tell an omitted one from an employee with no end date — **omitting it clears any stored end date**. The four wage *rates* are plain numbers, so an omitted rate is indistinguishable from a genuine `0.0` and **will set that wage to zero**. Always send both.

#### Update the POS instructor only

```json
{
  "id": 15,
  "posIdentifier": "1141583",
  "firstName": "Sam",
  "lastName": "Smith",
  "dateOfBirth": "1990-06-22",
  "actionUpsertInFlaik": false,
  "actionUpsertPosInstructor": true,
  "upsertPosInstructor": {
    "posInstructorEmployeeTypeCode": "2",
    "posInstructorPriorityRanking": "3"
  }
}
```

**What happens to fields you leave out:** on the POS instructor, omitted fields are **preserved** — the integration reads the current profile and writes back only what you supplied. Omitting `posInstructorEmployeeTypeCode` on an update keeps the existing employment type rather than resetting it.

> **Requires POS Integration API 2.6.0 or later** — see Prerequisites. Preserve-on-omit is a 2.6.0 behaviour. Below it, this partial update is rejected outright, and omitting rank or lesson location silently overwrites them.

> **`firstName`, `lastName` and `dateOfBirth` are always required**, on updates as well as creates, even when the action you are performing does not change them.

***

### 5. Archive an employee in Flaik

Archiving removes someone from active staff management without deleting them. Set the top-level `status` to `2` (Archived) with `actionUpsertInFlaik: true`.

```json
{
  "id": 15,
  "firstName": "Sam",
  "lastName": "Smith",
  "dateOfBirth": "1990-06-22",
  "email": "sam.smith@example.com",
  "status": 2,
  "actionUpsertInFlaik": true
}
```

`status` accepts `1` Active, `2` Archived, `3` Candidate (talent pool). Any other value is rejected with a 400.

**What archiving does:** the employee's record is retained — it is not deleted — but they drop out of the active staff roster, which filters on active status. They will no longer appear in staff management as a current employee.

**Confirm it landed:** poll the status endpoint; `actionUpsertInFlaikEmployeeWasCreated` will be `false` (an update, not a create) and `actionUpsertInFlaikHasError` will be absent or `false`.

> **Archiving in Flaik does not touch the POS.** It is a Flaik-side status only. To deactivate the same person in the POS, combine this with scenarios 6 and 7 in the same request, or send a follow-up call.

***

### 6. Make an employee inactive in RTP

Set the POS employee's **lifecycle** status to inactive with `posEmployeeStatusCode: "2"`.

```json
{
  "id": 15,
  "posIdentifier": "1141597",
  "firstName": "Sam",
  "lastName": "Smith",
  "dateOfBirth": "1990-06-22",
  "actionUpsertInFlaik": false,
  "actionUpsertPosEmployee": true,
  "upsertPosEmployee": {
    "posEmployeeId": "EMP123456",
    "posEmployeeStatusCode": "2"
  }
}
```

> **Use `posEmployeeStatusCode`, not `posEmployeeTypeCode`.** The status field is the lifecycle (`1` Active, `2` Inactive); the type field is the kind of employment. Sending `2` to the type field does not error — it silently reclassifies the person's employment type while leaving them active.

***

### 7. Make an instructor inactive in RTP

The instructor profile has its own lifecycle status, separate from the employee's. Set `posProfileStatus` to `2`.

```json
{
  "id": 15,
  "posIdentifier": "1141583",
  "firstName": "Sam",
  "lastName": "Smith",
  "dateOfBirth": "1990-06-22",
  "actionUpsertInFlaik": false,
  "actionUpsertPosInstructor": true,
  "upsertPosInstructor": {
    "posProfileStatus": "2"
  }
}
```

This is a minimal payload by design — you do not need to resend the instructor's location, rank, supervisor or employment type. Those are preserved, and a deactivation will not collaterally change them.

> **Requires POS Integration API 2.6.0 or later** — see Prerequisites. On 2.5.x this minimal deactivation is rejected, and a padded-out version would silently reset the instructor's rank and lesson location as a side effect of deactivating them. Upgrade before relying on this flow.

#### Deactivating both at once

An employee and their instructor profile are independent records in RTP. Deactivating one does not deactivate the other. To retire someone completely, send both in a single request:

```json
{
  "id": 15,
  "posIdentifier": "1141583",
  "firstName": "Sam",
  "lastName": "Smith",
  "dateOfBirth": "1990-06-22",
  "actionUpsertInFlaik": false,
  "actionUpsertPosEmployee": true,
  "actionUpsertPosInstructor": true,
  "upsertPosEmployee": {
    "posEmployeeId": "EMP123456",
    "posEmployeeStatusCode": "2"
  },
  "upsertPosInstructor": {
    "posProfileStatus": "2"
  }
}
```

Add `"status": 2` and `"actionUpsertInFlaik": true` to archive them in Flaik in the same call.

> **Verifying deactivation directly in RTP:** RTP **versions** these profiles. Each update inserts a new row and marks the previous one `StatusCode = 3` (Changed). If you query the RTP tables to confirm, read the row with the **highest `SequenceNumber`** for that profile — an unordered read can return a superseded version and make a successful deactivation look like it landed the wrong status.

***

### Choosing your actions at a glance

| Goal                       | `InFlaik` | `PosPerson` | `PosEmployee` | `PosInstructor` | Key field                              |
| -------------------------- | --------- | ----------- | ------------- | --------------- | -------------------------------------- |
| Create in Flaik only       | ✅         |             |               |                 | `primaryTeachingDisciplineId` required |
| Create in POS only         |           | ✅           | ✅             | ✅               | `posEmployeeId` required               |
| Create in both             | ✅         | ✅           | ✅             | ✅               | as above                               |
| Update Flaik record        | ✅         |             |               |                 | `id`                                   |
| Update POS instructor      |           |             |               | ✅               | `id` + `posIdentifier`                 |
| Archive in Flaik           | ✅         |             |               |                 | `status: 2`                            |
| Employee inactive in RTP   |           |             | ✅             |                 | `posEmployeeStatusCode: "2"`           |
| Instructor inactive in RTP |           |             |               | ✅               | `posProfileStatus: "2"`                |

***

Need help with employee data ingest? Contact <resortsupport@flaik.com>.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://knowledgebase.flaik.com/flaik-knowledge-base/for-it-specialists/3.-flaik-connect-api/employee-management/common-scenarios.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
