> 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/search-by-identifier.md).

# Search by Identifier

### Overview

Searches one identifier — typically the payroll id your HR system holds — across Flaik **and** the resort's POS in a single call, and returns everything it matched: the Flaik employee id, and every POS profile found by either of the two POS lookups, including each profile's IPCode and active/inactive status.

Its primary job is the **returning-seasonal check**: before creating an employee for the new season, search their payroll id. If a surviving POS profile exists from a previous season, take its IPCode from the response and pass it as `posIdentifier` on [Upsert Employee](https://knowledgebase.flaik.com/flaik-knowledge-base/for-it-specialists/3.-flaik-connect-api/employee-management/upsert-employee) — the existing profile is refreshed instead of a duplicate being created.

This is a read-only lookup; nothing is written.

> **How this differs from** [**Search Employee**](https://knowledgebase.flaik.com/flaik-knowledge-base/for-it-specialists/3.-flaik-connect-api/employee-management/search-employee)**:** Search Employee takes several criteria (name, email, ids) and returns a single flat match. Search by Identifier takes exactly one string, runs both POS lookups, and returns **all** matches with their status — it is the one to use for payroll-id lookups and season-start dedupe.

### Authentication

```http
Authorization: Bearer {access_token}
```

Requires `flaik.connect.api.read` **or** `flaik.connect.api.write`. Unlike the rest of the employee group, a read-only token is sufficient — this endpoint writes nothing. Legacy Enterprise scopes are **not** accepted here.

### Endpoint

```http
POST {api-url}/api/employee/searchByIdentifier
Content-Type: application/json
```

#### Request

| Field        | Type   | Description                                                                               |
| ------------ | ------ | ----------------------------------------------------------------------------------------- |
| `identifier` | string | **Required.** The identifier to search — e.g. `EMP1324`. Must not be blank or whitespace. |

```json
{ "identifier": "38292652" }
```

#### What gets searched

Three lookups run from the one identifier:

1. **Flaik** — exact match on the employee's payroll identifier (`payrollIdentifier` as submitted on the upsert).
2. **POS by EmployeeID** — resolves **active** employees only. RTP removes the EmployeeID when someone stops being an active employee, so a returning seasonal will *not* be found by this lookup.
3. **POS by AlternateId** — the payroll id stored on the POS profile (profile type 99). This is the **durable** key that survives seasonal churn, and it is how a returning seasonal's surviving profile is found.

The two POS lookups run in parallel and their results are merged, de-duplicated on IPCode.

### Reading the response — in this order

**1. Check `posSearchSupported` first.** `false` means the POS search **did not run** — the tenant's POS integration is disabled, or the resort's POS type does not support these lookups (they require the RTP integration with POS Integration API 2.6.0+). When it is `false`, the POS found-flags are not evidence that no profile exists. `true` with no matches means the search ran and genuinely found nothing.

**2. Take the IPCode from `posMatches[].posUniqueIdentifier`, not from `posIdentifier`.** The top-level `posIdentifier` is a convenience field populated **only** when the *EmployeeID* lookup matched exactly one profile — the unambiguous-active case. For a returning seasonal (AlternateId-only match) it is `null` **by design**. A client that reads only `posIdentifier` will fail on precisely the case this endpoint exists for.

**3. `matchedOn` tells you which lookup found each profile:** `"EmployeeId"`, `"AlternateId"`, or `"Both"`. A profile found by both lookups appears once, marked `"Both"`. Note that employees originally created through Flaik Connect's upsert carry their POS EmployeeID as their AlternateId, so active upsert-created employees normally come back as `"Both"`.

#### Example — active employee

```json
{
  "identifier": "38292652",
  "foundInFlaik": false,
  "flaikEmployeeId": null,
  "posSearchSupported": true,
  "foundInPosByEmployeeId": true,
  "foundInPosByAlternateId": true,
  "posIdentifier": "1141626",
  "posMatches": [
    {
      "posUniqueIdentifier": "1141626",
      "matchedOn": "Both",
      "posEmployeeIdentifier": "38292652",
      "posEmployeeTypeCode": "1", "posEmployeeTypeName": "Employee",
      "posEmployeeDepartmentCode": "1", "posEmployeeDepartmentName": "Ski School",
      "posEmployeeResortCode": "1", "posEmployeeResortName": "QBert",
      "posEmployeeStatusCode": "1", "posEmployeeStatusName": "Active"
    }
  ]
}
```

#### Example — returning seasonal (the case this endpoint exists for)

The employee is inactive in RTP, so the EmployeeID lookup finds nothing — but the AlternateId profile survives:

```json
{
  "identifier": "38292653",
  "foundInFlaik": false,
  "flaikEmployeeId": null,
  "posSearchSupported": true,
  "foundInPosByEmployeeId": false,
  "foundInPosByAlternateId": true,
  "posIdentifier": null,
  "posMatches": [
    {
      "posUniqueIdentifier": "1141627",
      "matchedOn": "AlternateId",
      "posEmployeeIdentifier": "",
      "posEmployeeTypeCode": "1", "posEmployeeTypeName": "Employee",
      "posEmployeeDepartmentCode": "1", "posEmployeeDepartmentName": "Ski School",
      "posEmployeeResortCode": "1", "posEmployeeResortName": "QBert",
      "posEmployeeStatusCode": "2", "posEmployeeStatusName": "Inactive"
    }
  ]
}
```

Here the IPCode to reuse is `posMatches[0].posUniqueIdentifier` (`"1141627"`) — note `posIdentifier` is `null`.

#### Response fields

| Field                                                                  | Type     | Description                                                                                             |
| ---------------------------------------------------------------------- | -------- | ------------------------------------------------------------------------------------------------------- |
| `identifier`                                                           | string   | The identifier searched, echoed back                                                                    |
| `foundInFlaik`                                                         | boolean  | A Flaik employee has this payroll identifier                                                            |
| `flaikEmployeeId`                                                      | integer? | The matching Flaik employee id — pass as `id` on an upsert to update that record                        |
| `posSearchSupported`                                                   | boolean  | **Read first.** `false` = the POS search did not run; do not treat the POS flags as "no profile exists" |
| `foundInPosByEmployeeId`                                               | boolean  | The EmployeeID lookup (active employees only) matched                                                   |
| `foundInPosByAlternateId`                                              | boolean  | The AlternateId lookup (survives seasonal churn) matched                                                |
| `posIdentifier`                                                        | string?  | IPCode from the EmployeeID match, **only when exactly one profile matched it**; otherwise `null`        |
| `posMatches[]`                                                         | array    | Every POS profile matched by either lookup, de-duplicated on IPCode                                     |
| `posMatches[].posUniqueIdentifier`                                     | string   | **The IPCode** — feed this to the upsert's `posIdentifier` to reuse the profile                         |
| `posMatches[].matchedOn`                                               | string   | `"EmployeeId"`, `"AlternateId"` or `"Both"`                                                             |
| `posMatches[].posEmployeeIdentifier`                                   | string   | The POS EmployeeID (empty on inactive profiles — RTP removes it)                                        |
| `posMatches[].posEmployeeTypeCode` / `posEmployeeTypeName`             | string   | POS employee type                                                                                       |
| `posMatches[].posEmployeeDepartmentCode` / `posEmployeeDepartmentName` | string   | Department                                                                                              |
| `posMatches[].posEmployeeResortCode` / `posEmployeeResortName`         | string   | Resort                                                                                                  |
| `posMatches[].posEmployeeStatusCode` / `posEmployeeStatusName`         | string   | **Active/inactive status** — `1`/`Active`, `2`/`Inactive`. The dedupe signal                            |

The POS `governmentIdentifier` is deliberately **not** included in this response, even though the POS holds one.

### Response Codes

| HTTP Status | Meaning                                                                                     |
| ----------- | ------------------------------------------------------------------------------------------- |
| `200`       | Always returned for a valid request — **including when nothing was found**. Read the flags. |
| `400`       | `identifier` missing, blank, or whitespace-only                                             |
| `401`       | Missing or invalid access token                                                             |
| `403`       | Token does not include `flaik.connect.api.read` or `flaik.connect.api.write`                |

There is no `204` and no `404` — "not found" is a `200` with all found-flags `false`. This differs from [Search Employee](https://knowledgebase.flaik.com/flaik-knowledge-base/for-it-specialists/3.-flaik-connect-api/employee-management/search-employee), which returns `204`.

### Typical use — season-start returning-seasonal check

1. `POST /api/employee/searchByIdentifier` with the payroll id from your HR system.
2. `posSearchSupported: false` → the POS cannot be searched for this resort; fall back to your normal create flow.
3. All found-flags `false` → genuinely new person; create via [Upsert Employee](https://knowledgebase.flaik.com/flaik-knowledge-base/for-it-specialists/3.-flaik-connect-api/employee-management/upsert-employee) without `posIdentifier`.
4. A POS match exists → take `posMatches[].posUniqueIdentifier` (preferring the profile whose status/department you expect) and submit the upsert **with `posIdentifier` set to that IPCode** — the surviving profile is refreshed for the new season instead of a duplicate being created.
5. `foundInFlaik: true` → additionally pass `flaikEmployeeId` as the upsert's `id` so the Flaik record is updated rather than recreated.

> **If your employees were created through Flaik Connect:** the AlternateId on their POS profile is their POS EmployeeID (not the Flaik payroll identifier), because that is what the upsert writes to the POS. Search with the identifier your integration submitted as `posEmployeeId`. An identifier that matches in Flaik *and* the POS in one call requires those two values to be the same string.

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/search-by-identifier.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.
