> ## Documentation Index
> Fetch the complete documentation index at: https://developers.luccasoftware.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Get Started With Employee Attributes

> Learn what employee-attributes are and how to use them to read any employee property in a uniform way.

## What Are Employee Attributes?

The employee data model in the Lucca API is spread across several **primary resources**: [`employee`](../employees/employee), [`employee-personal-record`](../employees/employee-personal-record), [`employment`](../employments/employment), and [`job-position`](../employments/job-position). Each carries a set of **system built-in properties** defined by Lucca (e.g. `employee.givenName`, `personal.legalGender`, `jobPosition.manager`). In addition, your organization can define its own **custom properties** (e.g. a "T-shirt size" field) and attach them to any of these primary resources.

In practice, this means a single piece of information about an employee may live on any of these resources, as either a system or custom property.

**Employee attributes provide a single, uniform endpoint to access any property — system built-in or custom — from any primary API resource**, regardless of where it is stored.

An `employee-attribute` is the value of one specific property for one specific employee. Each attribute is described by an [`employee-attribute-definition`](./employee-attribute-definition), which declares what the property is, what type it carries, and which primary resource it targets (`employee`, `employment`, or `job-position`).

<Note>
  **System built-in properties** (e.g. `employee.givenName`, `jobPosition.manager`) are read-only through this endpoint. To update them, use the write endpoints of the corresponding primary resource (e.g. `PATCH /lucca-api/employees/{id}`).

  **Custom properties** (e.g. `e_tShirtSize`, `e_children`) are exclusively managed — only read as of now — through the `employee-attributes` and `employee-attribute-definitions` endpoints. There is no other API endpoint for them.
</Note>

***

## Key Concepts

### Definitions vs. Values

Employee attributes unify two kinds of properties into a single model:

* **System built-in properties** that Lucca defines on primary resources (e.g. `employee.givenName`, `jobPosition.manager`).
* **Custom properties** that your organization creates and attaches to a primary resource (e.g. `e_tShirtSize`).

Both are accessed through the same pair of concepts:

<CardGroup cols={2}>
  <Card title="employee-attribute-definition" icon="book">
    Describes a property: its `id`, human-readable `name`, the JSON `schema` of its value, and the `targetType` (`employee`, `employment`, or `job-position`) indicating which primary resource it belongs to. Definitions are either provided by Lucca (for system properties) or created by your organization (for custom properties).
  </Card>

  <Card title="employee-attribute" icon="tag">
    The actual value of a definition for a given employee. Contains the `value` itself, a reference to its `definition`, the `employee` it belongs to, and an `applicability` window indicating the date range over which the value is valid.
  </Card>
</CardGroup>

### System vs. Custom Attributes

Although both appear as `employee-attribute` values, system and custom attributes differ in how they are managed:

|                           | System                                                                                      | Custom                                                   |
| :------------------------ | :------------------------------------------------------------------------------------------ | :------------------------------------------------------- |
| **Origin**                | Defined by Lucca. Present on every account.                                                 | Created by your organization to fit your needs.          |
| **Examples**              | `employee.givenName`, `employee.birthDate`, `jobPosition.manager`, `jobPosition.department` | `e_tShirtSize`, `e_favoriteColor`, `e_children`          |
| **Read via**              | Primary resource endpoints **or** `employee-attributes`                                     | `employee-attributes`                                    |
| **Write via**             | Primary resource endpoints (e.g. `PATCH /lucca-api/employees/{id}`)                         | Not implemented yet                                      |
| **Definition managed by** | Lucca — always present, cannot be modified.                                                 | Your organization, via `employee-attribute-definitions`. |

<Tip>
  Custom property IDs always start with `e_` (e.g. `e_tShirtSize`), making them easy to distinguish from system ones (e.g. `employee.givenName`).
</Tip>

### Applicability

Because many attributes come from time-bounded resources like `employment` or `job-position`, each `employee-attribute` exposes an **`applicability`** window:

```json theme={null}
"applicability": {
    "start": "2022-03-01",
    "end": "2024-11-30"
}
```

* `start` is the inclusive lower bound. `null` means "since the beginning of time".
* `end` is the inclusive upper bound. `null` means "until the end of time".
* For attributes without a temporal dimension (e.g. `employee.givenName`, `e_tShirtSize`), **both bounds are `null`**, meaning the value applies indefinitely.

Use the `?applicability.asOf={date}` query parameter to filter attributes to those valid on a specific date — for example, to retrieve the state of an employee on their first day.

### Multiple Values

Some definitions support **multiple values** per primary resource (e.g. "employee's children", where the same employee may have several entries). The `multipleValueHandling` property on the definition describes this behavior:

* `null` → single-valued: at most one attribute per employee for this definition.
* non-null → multi-valued: multiple attributes per employee are allowed, with a `sorting` direction and optional `sortingProperty` to order them.

***

## Access

### OAuth Scopes

| Scope                                      | Access                                                  |
| :----------------------------------------- | :------------------------------------------------------ |
| `employee-attribute-definitions.readonly`  | Read attribute definitions.                             |
| `employee-attribute-definitions.readwrite` | Read, create, update, and delete attribute definitions. |
| `employee-attributes.readonly`             | Read attribute values.                                  |
| `employee-attributes.readwrite`            | Read, create, update, and delete attribute values.      |

<Tip>For most read-only integration scenarios, the `employee-attributes.readonly` scope is sufficient. You only need `employee-attribute-definitions.readonly` if your integration needs to dynamically discover which attributes are available.</Tip>

### HR File Sections and Business Establishments

Beyond OAuth scopes, two additional constraints apply when reading employee attributes:

* **Business establishments**: you may only access attributes of employees whose applicable business establishment (see `employee.applicableJobPosition.businessEstablishment`) is accessible to your client application.
* **HR file sections**: each attribute definition is associated with an employee hr file section. Sections are not exposed by the v5 Lucca API but are visible in the user interface. Your integration may only access attributes belonging to sections explicitly granted to it (see below).

#### Granting access to hr file sections

When configuring your OAuth client, the `employee-attributes.readonly` (or `.readwrite`) scope requires you to select the **specific hr file sections** your integration can read. Only attributes attached to one of the selected sections will be returned by the API.

<Warning>
  If you select all sections, the API will return **no employee-attribute at all** (i.e. responses will be empty).
</Warning>

<Tip>
  **Security best practice**: as a Lucca admin, create a **dedicated hr file section** for your integration and attach to it only the attributes it needs — no more.

  This approach:

  * Makes your integration's data footprint explicit and auditable.
  * Prevents accidental exposure of sensitive attributes attached to other sections.
  * Reduces the blast radius of a compromised access token: the attacker can only access attributes in the granted sections, not the entire account.
</Tip>

***

## Common Workflows

### 1. Discover Available Definitions

Before reading values, you may want to discover which attribute definitions exist on the account.

```http theme={null}
GET /lucca-api/employee-attribute-definitions?sort=name HTTP/1.1
Host: example.ilucca.net
Authorization: Bearer {ACCESS_TOKEN}
Api-Version: 2024-11-01
Accept: application/json
```

You can narrow results with these query parameters:

| Parameter    | Description                                                        |
| :----------- | :----------------------------------------------------------------- |
| `id`         | Filter by one or more definition IDs (comma-separated, max 100).   |
| `search`     | Find definitions whose name starts with the given string.          |
| `isArchived` | Filter by archival status.                                         |
| `sort`       | Sort by `id`, `name`, or `createdAt` (prefix with `-` to reverse). |

A definition response looks like this:

```json theme={null}
{
    "id": "e_tShirtSize",
    "type": "employee-attribute-definition",
    "url": "https://example.ilucca.net/lucca-api/employee-attribute-definitions/e_tShirtSize",
    "name": "T-shirt size",
    "targetType": "employee",
    "multipleValueHandling": null,
    "schema": {
        "$id": "/lucca-api/schemas/taxonomy-label-reference",
        "$schema": "https://json-schema.org/draft/2020-12/schema",
        "title": "taxonomy-label-reference",
        "description": "JSON representation of a reference to a taxonomy label",
        "type": ["object", "null"],
        "additionalProperties": false,
        "required": ["id"],
        "properties": {
            "id": {
                "type": "string",
                "minLength": 1
            },
            "type": {
                "type": "string",
                "const": "taxonomy-label",
                "readOnly": true
            },
            "url": {
                "type": "string",
                "format": "uri",
                "readOnly": true
            }
        }
    },
    "taxonomy": {
        "id": "45",
        "type": "taxonomy",
        "url": "https://example.ilucca.net/lucca-api/taxonomies/45"
    },
    "t9n": {
        "name": { "fr-FR": "Taille de t-shirt" }
    },
    "isArchived": false
}
```

The `targetType` tells you which underlying resource the value comes from:

| `targetType`   | Source                                                                                             |
| :------------- | :------------------------------------------------------------------------------------------------- |
| `employee`     | A system or custom property attached to the [`employee`](../employees/employee) resource           |
| `employment`   | A system or custom property attached to the [`employment`](../employments/employment) resource     |
| `job-position` | A system or custom property attached to the [`job-position`](../employments/job-position) resource |

***

### 2. Read Attributes for a Specific Employee

To fetch all current attribute values for a given employee, filter by `employee.id` and supply an `applicability.asOf` date:

```http theme={null}
GET /lucca-api/employee-attributes?employee.id=416&applicability.asOf=2026-03-24 HTTP/1.1
Host: example.ilucca.net
Authorization: Bearer {ACCESS_TOKEN}
Api-Version: 2024-11-01
Accept: application/json
```

| Query parameter      | Description                                                                                     |
| :------------------- | :---------------------------------------------------------------------------------------------- |
| `employee.id`        | Filter by employee ID(s) (comma-separated, max 100).                                            |
| `definition.id`      | Filter by definition ID(s) — useful when you only need specific fields.                         |
| `applicability.asOf` | Only return attributes whose applicability window includes this date.                           |
| `value`              | Filter by value. Supports dot-notation for object schemas (e.g. `value.e_childGivenName=John`). |
| `sort`               | Sort by `id`, `createdAt`, `value`, or `definition.id`.                                         |

A response item looks like this:

```json theme={null}
{
    "id": "34879",
    "type": "employee-attribute",
    "url": "https://example.ilucca.net/lucca-api/employee-attributes/34879",
    "definition": {
        "id": "givenName",
        "type": "employee-attribute-definition",
        "url": "https://example.ilucca.net/lucca-api/employee-attribute-definitions/givenName"
    },
    "employee": {
        "id": "416",
        "type": "employee",
        "url": "https://example.ilucca.net/lucca-api/employees/416"
    },
    "applicability": null,
    "value": "John",
    "createdAt": "2014-04-12T09:43:52.432Z",
    "lastUpdatedAt": "2014-04-12T09:43:52.432Z"
}
```

#### Filtering on `value`

The `value` query parameter lets you filter attributes by their actual value. For scalar values (strings, booleans, numbers), pass the value directly:

```http theme={null}
# All employees whose job title is "Software Engineer"
GET /lucca-api/employee-attributes?definition.id=jobPosition.jobTitle&value=Software Engineer HTTP/1.1
```

For **object-typed** attributes (i.e. definitions whose `schema.type` is `"object"`), use **dot-notation** to target a specific sub-property of the value:

```http theme={null}
# All "children" attributes where the child's given name is "Alice"
GET /lucca-api/employee-attributes?definition.id=e_children&value.e_childGivenName=Alice HTTP/1.1
```

<Note>
  Filtering on `value` performs a strict equality check. Partial matches and range filters are not supported.
</Note>

***

### 3. Read a Single Attribute

When you already know the attribute's `id`, retrieve it directly:

```http theme={null}
GET /lucca-api/employee-attributes/{id} HTTP/1.1
Host: example.ilucca.net
Authorization: Bearer {ACCESS_TOKEN}
Api-Version: 2024-11-01
Accept: application/json
```

***

## Understanding the `value` Property

The `value` type depends on the `schema` declared on the associated definition. Below are the most common schemas and their corresponding JSON representations:

| Schema `$id`                                  | JSON type of `value` | Example                                        |
| :-------------------------------------------- | :------------------- | :--------------------------------------------- |
| `/lucca-api/schemas/short-text`               | `string \| null`     | `"Software Engineer"`                          |
| `/lucca-api/schemas/long-text`                | `string \| null`     | `"Lorem ipsum..."`                             |
| `/lucca-api/schemas/boolean`                  | `boolean \| null`    | `true`                                         |
| `/lucca-api/schemas/int32`                    | `number \| null`     | `42`                                           |
| `/lucca-api/schemas/decimal`                  | `number \| null`     | `1.5`                                          |
| `/lucca-api/schemas/legacy-date`              | `string \| null`     | `"2025-01-01T00:00:00"`                        |
| `/lucca-api/schemas/email`                    | `string \| null`     | `"jdoe@example.org"`                           |
| `/lucca-api/schemas/employee-reference`       | `object \| null`     | `{"id": "416", "type": "employee", ...}`       |
| `/lucca-api/schemas/taxonomy-label-reference` | `object \| null`     | `{"id": "545", "type": "taxonomy-label", ...}` |

For `object`-typed schemas, the value is a JSON object whose properties each follow their own referenced schema. Use the definition's `propertyDescriptions` to discover and label each sub-property.

<Tip>All schemas are nullable — a `null` value means the attribute has no value set for this employee.</Tip>

### Listing Available Values for Taxonomy Properties

When a definition uses the `taxonomy-label-reference` schema, the employee can only pick from a predefined list of values. To retrieve that list, use the `taxonomy.id` from the definition and call:

```http theme={null}
GET /lucca-api/taxonomy-labels?taxonomy.id={taxonomyId} HTTP/1.1
Host: example.ilucca.net
Authorization: Bearer {ACCESS_TOKEN}
Api-Version: 2024-11-01
Accept: application/json
```

For example, the "T-shirt size" definition above has `"taxonomy": {"id": "45"}`. Calling `GET /lucca-api/taxonomy-labels?taxonomy.id=45` returns the available labels (Small, Medium, Large, etc.).

<Tip>This requires the `taxonomies.readonly` scope. See [Get Started With Taxonomies](../taxonomies/get-started) for a full walkthrough.</Tip>

***

## Example: Multi-valued Object Attribute (Children)

This example walks through a custom attribute representing an employee's dependent children. Because an employee may have several children, the definition uses `multipleValueHandling` to allow multiple values and declare how they should be sorted.

### The Definition

```json theme={null}
{
    "id": "e_children",
    "type": "employee-attribute-definition",
    "url": "https://example.ilucca.net/lucca-api/employee-attribute-definitions/e_children",
    "name": "Children",
    "targetType": "employee",
    "multipleValueHandling": {
        "sorting": "ascending",
        "sortingProperty": "e_childBirthDate"
    },
    "schema": {
        "type": "object",
        "properties": {
            "e_childGivenName": {
                "$ref": "/lucca-api/schemas/short-text"
            },
            "e_childFamilyName": {
                "$ref": "/lucca-api/schemas/short-text"
            },
            "e_childBirthDate": {
                "$ref": "/lucca-api/schemas/legacy-date"
            }
        }
    },
    "propertyDescriptions": {
        "e_childGivenName": {
            "name": "Given Name",
            "taxonomy": null,
            "sortOrder": 0,
            "t9n": {
                "name": {
                    "en-US": "First Name",
                    "fr-FR": "Prénom"
                }
            }
        },
        "e_childFamilyName": {
            "name": "Family Name",
            "taxonomy": null,
            "sortOrder": 1,
            "t9n": {
                "name": {
                    "en-US": "Last Name",
                    "fr-FR": "Nom de famille"
                }
            }
        },
        "e_childBirthDate": {
            "name": "Birth Date",
            "taxonomy": null,
            "sortOrder": 2,
            "t9n": {
                "name": {
                    "fr-FR": "Date de naissance"
                }
            }
        }
    },
    "taxonomy": null,
    "isArchived": false,
    "t9n": {
        "name": {
            "fr-FR": "Enfants à charge"
        }
    }
}
```

Key points about this definition:

* **`multipleValueHandling` is non-null** — multiple `employee-attribute` records can exist for the same employee under this definition (one per child).
* **`sortingProperty: "e_childBirthDate"`** — clients should display children sorted by their birth date in ascending order.
* **`propertyDescriptions`** — provides human-readable labels and translation keys for each object property, useful when building a UI.

### The Corresponding Attributes

Querying `GET /lucca-api/employee-attributes?employee.id=416&definition.id=e_children` returns one item per child:

```json theme={null}
{
    "type": "employee-attributes",
    "url": "https://example.ilucca.net/lucca-api/employee-attributes?employee.id=416&definition.id=e_children",
    "items": [
        {
            "id": "87601",
            "type": "employee-attribute",
            "url": "https://example.ilucca.net/lucca-api/employee-attributes/87601",
            "definition": {
                "id": "e_children",
                "type": "employee-attribute-definition",
                "url": "https://example.ilucca.net/lucca-api/employee-attribute-definitions/e_children"
            },
            "employee": {
                "id": "416",
                "type": "employee",
                "url": "https://example.ilucca.net/lucca-api/employees/416"
            },
            "applicability": null,
            "value": {
                "e_childGivenName": "Alice",
                "e_childFamilyName": "Doe",
                "e_childBirthDate": "2015-06-12T00:00:00"
            },
            "createdAt": "2021-09-01T08:00:00.000Z",
            "lastUpdatedAt": "2021-09-01T08:00:00.000Z"
        },
        {
            "id": "87602",
            "type": "employee-attribute",
            "url": "https://example.ilucca.net/lucca-api/employee-attributes/87602",
            "definition": {
                "id": "e_children",
                "type": "employee-attribute-definition",
                "url": "https://example.ilucca.net/lucca-api/employee-attribute-definitions/e_children"
            },
            "employee": {
                "id": "416",
                "type": "employee",
                "url": "https://example.ilucca.net/lucca-api/employees/416"
            },
            "applicability": null,
            "value": {
                "e_childGivenName": "Bob",
                "e_childFamilyName": "Doe",
                "e_childBirthDate": "2018-03-22T00:00:00"
            },
            "createdAt": "2021-09-01T08:00:00.000Z",
            "lastUpdatedAt": "2021-09-01T08:00:00.000Z"
        }
    ]
}
```

<Tip>
  Because `applicability` is `null` on both items, this attribute has no temporal dimension — the employee's children list is not tied to an employment or job-position period. Use `?sort=value.e_childBirthDate` to retrieve them already sorted by birth date, matching the `sortingProperty` declared on the definition.
</Tip>

***

## Paginating Results

Like all collection endpoints, `/lucca-api/employee-attributes` is paginated. Use `?include=totalCount,links` to get the total count and cursor links for navigating pages. The default and maximum page size is defined in the [API Reference](/api-reference/latest).

```http theme={null}
GET /lucca-api/employee-attributes?employee.id=416&applicability.asOf=2026-03-24&include=totalCount,links&limit=50 HTTP/1.1
Host: example.ilucca.net
Authorization: Bearer {ACCESS_TOKEN}
Api-Version: 2024-11-01
```

<CardGroup cols={2}>
  <Card title="Pagination" href="/documentation/using-api/paging" icon="forward">
    Learn how cursor-based pagination works.
  </Card>

  <Card title="Filtering" href="/documentation/using-api/filtering" icon="filter">
    Learn more about filtering collections.
  </Card>
</CardGroup>
