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

# Directory Sync

> Keep your directory current by connecting an HRIS or directory solution for automatic sync, or import users from a file.

Keep your
[directory](/en/identity/directory/directory-overview) populated and up to date
from the system that's the source of truth for who's in your organization. There
are two ways to do it:

<CardGroup cols={2}>
  <Card title="Connect a source system" icon="plug">
    Link a **live source** (an **HRIS** such as **Workday** or **BambooHR**, or
    another **directory solution**) and Iru pulls users from it and syncs on a
    schedule, creating, updating, and removing users on its own. More providers are
    on the way.
  </Card>

  <Card title="Import a file (manual)" icon="file-csv" href="/en/identity/directory/importing-users">
    No direct connector for your system? Export your users to a **CSV** (from a
    legacy HR system, a **Student Information System (SIS)**, or anything you can
    produce a file from) and upload it. Re-upload an updated export whenever your
    list changes to keep users current.
  </Card>
</CardGroup>

When you connect a live source, updates flow into Iru on their own, so when
someone is hired, changes roles, or leaves, your directory follows with no manual
work. The rest of this guide covers connecting a source system; for the manual
route, see [CSV import](/en/identity/directory/importing-users).

Today you can connect the HR systems **Workday** and **BambooHR**, with more
providers (including other directory solutions) on the way. Setup is the same
guided flow for each; only a couple of steps differ by provider.

<Note>
  Connecting a source system needs administrator access to your Iru tenant and an
  administrator account for that system. Depending on the provider, you either
  enter integration credentials in Iru or authorize Iru in the provider's own
  consent window. The connection only **reads** users from the source; it never
  writes back to it.
</Note>

<Frame caption="Connected sources are listed under Directory, on the Sync tab.">
  <img src="https://mintcdn.com/iru/Pd7a0-sHKi0jGjE6/assets/media/images/directory-sync-list.webp?fit=max&auto=format&n=Pd7a0-sHKi0jGjE6&q=85&s=bdfcf859acb179f4473455ec5f090787" alt="The Directory page in Iru on the Sync tab, listing connected sources with their status." width="2000" height="1098" data-path="assets/media/images/directory-sync-list.webp" />
</Frame>

## How it works at a glance

1. **Choose** your provider.
2. **Connect:** enter credentials in Iru (Workday) or authorize Iru in your provider
   (BambooHR) so it can read your user data.
3. **Configure** (some providers only): tell Iru where your data lives.
4. **Map** the source's fields to Iru fields.
5. **Enable:** turn on syncing and choose how often it runs.

```mermaid theme={null}
flowchart LR
  connect["Connect<br/>+ authorize"] --> discover["Iru reads<br/>available fields"]
  discover --> map["Map fields<br/>source → Iru"]
  map --> enable["Enable"]
  enable --> sync["Scheduled or<br/>on-demand sync"]
  sync -->|"create / update / remove"| dir["Directory"]
  sync -->|"problems"| errors["Sync errors to review"]
```

Once a connection is enabled, Iru syncs on the **interval** you set, from every
**30 minutes** up to once per **week**, or **manual only** if you prefer to run
syncs yourself with **Sync now**.

## Ideas that apply to every connection

* **Your source system leads.** Once connected, it's the authority on user data;
  Iru reflects what it sends.
* **Every user needs a stable ID.** You pick one field that uniquely and
  permanently identifies each user, so Iru always updates the right record.
* **You decide how fields line up.** Iru doesn't guess. You map each source field
  to the matching Iru field, and can transform values with **IQL** when they don't
  line up one-to-one.

## Set it up

<Steps>
  <Step title="Choose your provider">
    In **Directory → Sync**, select **Connect Source** and pick your provider:
    **Workday** or **BambooHR**.

    <Frame caption="Connect Source lists the source systems you can connect.">
      <img src="https://mintcdn.com/iru/Pd7a0-sHKi0jGjE6/assets/media/images/connect-source.png?fit=max&auto=format&n=Pd7a0-sHKi0jGjE6&q=85&s=66f7f44acd51140036fbe7ae9707faa3" alt="The Select user source picker opened from Connect Source, offering Workday, Bamboo, and an Other Sources option marked Coming Soon." width="1188" height="764" data-path="assets/media/images/connect-source.png" />
    </Frame>
  </Step>

  <Step title="Connect to your provider">
    Give the connection a **display name** (and optional **description**), then give
    Iru read access to your provider. How you do that depends on the provider:

    * **Workday:** enter the instance host, Workday tenant, Integration System User,
      and password in Iru.
    * **BambooHR:** enter your **company domain** in Iru, then authorize in a
      **BambooHR window**. Sign in to BambooHR and select **Allow Access** on the
      **Share access with Iru Identity** screen. Your BambooHR credentials go to
      BambooHR, not to Iru, and there is no API key to enter. Finish authorizing
      within **15 minutes**, or return to Iru and start the connection again.

    See the [provider guides](#choose-your-provider) for the exact fields and screens.

    <Frame caption="Workday connection: Integration System User credentials entered in Iru.">
      <img src="https://mintcdn.com/iru/60YZAZS1iNMrBv2w/assets/media/images/iru-identity-connect-workday.png?fit=max&auto=format&n=60YZAZS1iNMrBv2w&q=85&s=637b56461035f9b7762f63e0d01daabb" alt="The Connect with Workday step asking for Integration user and Password." width="1266" height="267" data-path="assets/media/images/iru-identity-connect-workday.png" />
    </Frame>

    <Tip>
      Use a dedicated admin / integration account where you can, so the connection
      keeps working regardless of any one user's status.
    </Tip>
  </Step>

  <Step title="Configure where your data lives (some providers)">
    Some providers need you to point Iru at the right data source. **Workday** asks
    for the **report name** that exposes the worker fields you want; the Integration
    System User from the previous step is what runs that report. **BambooHR** reads
    its standard employee directory, so it skips this step. See the
    [provider guides](#choose-your-provider) below.
  </Step>

  <Step title="Map your data to Iru">
    Iru reads the fields your provider makes available and lays them out for you to
    match. See [Map your data](#map-your-data) below.
  </Step>

  <Step title="Finish and enable">
    Save your mappings to finish setup. A new connection starts **disabled**, so
    nothing syncs until you've reviewed it, then **Enable** it to run the first
    import. Set the **sync interval** on the connection's Configuration tab, or leave
    it on **Manual only** and use **Sync now** when you want an update.
  </Step>
</Steps>

## Map your data

Mapping is where most of the setup happens: connecting your source's fields to the matching
fields in Iru.

<Frame caption="The Mapping tab: a unique-identifier expression plus one row per attribute, each filled by a source field or an IQL expression.">
  <img src="https://mintcdn.com/iru/yv46VZ-WbN1GdStp/assets/media/images/sync-connection-mapping.webp?fit=max&auto=format&n=yv46VZ-WbN1GdStp&q=85&s=aad2660a55fb85c678742bdbc11b9596" alt="The Mapping tab of a connection, showing the Unique user identifier field and an Attributes list mapping Bamboo fields (firstName, lastName, workEmail) to Iru attributes (name.firstName, name.lastName, primaryEmail.email), with some values built from IQL expressions." width="1888" height="1036" data-path="assets/media/images/sync-connection-mapping.webp" />
</Frame>

### Set a unique identifier

Choose the field that uniquely identifies each user, often an **employee ID** or
similar stable identifier. Iru relies on one stable value per user to update the
*right* record on every sync, even when names or emails change.

<Warning>
  Pick something that never changes for a user. **Once you save the connection,
  the unique identifier can't be changed.** Changing it would break Iru's ability
  to recognize the users it has already imported.
</Warning>

### Match fields to Iru

For each Iru attribute, pick the source field that should fill it. Four attributes
are **required** and always mapped:

* **Email**
* **First name**
* **Last name**
* **Username**

Any attribute you've marked required in your
[schema](/en/identity/directory/schema) is required here too. Everything
else is optional, but mapping it brings over the full picture of each user:
title, department, manager, location, and more.

### Transform values with IQL

Most fields are a simple pick-and-go. When the value you want needs to be *built*
from a field rather than copied as-is, write a short **IQL** expression instead. As
you type, Iru suggests the available fields and checks your expression, so you
catch a typo or a missing field *before* you save, not during a sync. See
[Attribute mapping](/en/identity/directory/attribute-mapping#writing-expressions) and
[IQL expressions](/en/identity/getting-started/iql-expressions) for the full syntax.

#### How a field name is read

IQL reads a field name as code. A bare name works when it is a valid IQL
identifier: it starts with an ASCII letter or underscore, and every later
character is an ASCII letter, number, or underscore. `first_name` qualifies, so
you write it as it is. A dot joins valid names to reach a nested value, as in
`name.givenName`. A field whose own name contains a dot is one key, so you look
it up as `__source["name.givenName"]`.

Some source systems send names that fall outside that rule:

* Names with spaces, hyphens, colons, or other symbols, such as `Email - Work` or
  `urn:ietf:params:scim:schemas:extension:enterprise:2.0:User:department`
* Names that are also IQL keywords, such as `in`, `null`, `true`, or `if`

Written bare, `Email - Work` reads as `Email` minus `Work`, and `in` reads as the
membership operator. To read the field, look it up by its exact name in `__source`, a
map of every field from the source:

```
__source["Email - Work"]
```

When you pick or type one of these fields in the mapping editor, Iru rewrites it
to `__source["…"]`. You can use that form for any field, and it works inside a
longer expression like any other value:

```
__source["Email - Work"].lowerAscii()
```

If a field name contains a double quote (`"`) or a backslash (`\`), put a
backslash in front of each one inside the brackets. A field named `Title "Legal"`
is written `__source["Title \"Legal\""]`. The editor adds those backslashes when
it rewrites the field.

Common examples (use your provider's own field names):

* **Build a username from an email** (everything before the `@`):
  `email.split("@")[0]`
* **Combine two fields** into one value:
  `firstName + " " + lastName`
* **Prefer one field, fall back to another** when the first is blank:
  `optional.ofNonZeroValue(workEmail).orValue(homeEmail)`

<Tip>
  If a field is sometimes blank, guard against it so the sync doesn't trip on empty
  records. Wrap the value with `optional.ofNonZeroValue(...).orValue("")` before
  transforming it. For example, only deriving a username when an email exists:
  `optional.ofNonZeroValue(email).orValue("").split("@")[0]`
</Tip>

## Choose your provider

The flow is the same for each; these guides cover the steps that differ.

<CardGroup cols={2}>
  <Card title="Connect Workday" icon="briefcase" href="/en/identity/directory/hris-workday">
    Read workers from a Workday report. Includes the report and integration-user
    step.
  </Card>

  <Card title="Connect BambooHR" icon="seedling" href="/en/identity/directory/hris-bamboohr">
    Read from BambooHR's standard employee directory. No report to configure.
  </Card>
</CardGroup>

| Step | Workday | BambooHR |
| - | - | - |
| Connect | Credentials entered in Iru | Sign in and **Allow Access** in BambooHR |
| Configure a report | Yes | No (standard fields) |
| Map fields (unique ID, required fields, IQL) | Yes | Yes |
| Enable and sync on a schedule | Yes | Yes |

## What happens on each sync

Once enabled, Iru syncs on the interval you choose and reconciles your directory
with the source system:

| Change at the source | What Iru does |
| - | - |
| A new user appears | Creates a matching user in your directory |
| A user's details change | Updates the user's profile attributes |
| A user is no longer present | Removes the user from your directory |

As profiles arrive and change, [Auto Groups](/en/identity/directory/auto-groups)
update their membership automatically, so access follows users without manual
work.

<Frame caption="A connection's Effective Users: the users currently synced in from the source.">
  <img src="https://mintcdn.com/iru/yv46VZ-WbN1GdStp/assets/media/images/sync-connection-effective-users.webp?fit=max&auto=format&n=yv46VZ-WbN1GdStp&q=85&s=811705e35cdd3db62a8016e32e0635fe" alt="The Effective Users tab of a connection, listing synced users such as Ashley Adams and Charlotte Abbott with their created date and ID." width="1888" height="1036" data-path="assets/media/images/sync-connection-effective-users.webp" />
</Frame>

## Sync schedule and on-demand sync

On a connection's **Configuration** tab, set **Sync frequency** with the
**Interval** control. Choose how often Iru pulls the latest directory, or set it to
**Manual only** and sync on demand.

Available intervals:

* Manual only (no automatic sync)
* Every 30 minutes
* Every hour
* Every 2 hours
* Every 4 hours
* Every 8 hours
* Every 12 hours
* Every day
* Every 2 days
* Every week

<Frame caption="Choosing how often Iru syncs the connection.">
  <img src="https://mintcdn.com/iru/60YZAZS1iNMrBv2w/assets/media/images/iru-identity-sync-frequency.png?fit=max&auto=format&n=60YZAZS1iNMrBv2w&q=85&s=8f34a961b593788e00bde0adff90a0a8" alt="The Sync schedule section with the Interval menu open, listing Manual only and options from Every 30 minutes through Every week." width="1012" height="716" data-path="assets/media/images/iru-identity-sync-frequency.png" />
</Frame>

On the **Sync** tab, use **Sync now** to start a run immediately, and **Refresh** to
reload the list of sync runs. Each run reads everyone from your directory source and
adds or updates them in Iru. Select a run to see what it did and anything it could
not sync. A failed run tries again at the next scheduled sync.

## Manage the connection over time

From a connection's detail page you can:

* **Re-authenticate:** submit fresh credentials, or approve access with your
  provider again, when the connection expires or is rejected, without touching your
  mappings.
* **Edit your configuration or mappings:** adjust what's imported as your needs
  evolve.
* **Set the sync interval** or run **Sync now**.
* **Force attribute sync** (Workday): re-read the latest available fields from
  your report without waiting.
* **Review activity, effective users, and sync errors:** see what's flowing in
  and spot anything that needs attention.
* **Enable or disable** the connection, or remove it.

<Frame caption="A connection's detail page: status, connection health, and Re-authenticate.">
  <img src="https://mintcdn.com/iru/60YZAZS1iNMrBv2w/assets/media/images/iru-identity-start-reauthentication-bamboo.png?fit=max&auto=format&n=60YZAZS1iNMrBv2w&q=85&s=a3415b8304ce762d249f68120a108691" alt="The Configuration tab of a Bamboo connection showing Status Enabled, connection details with Needs re-authentication, and a Re-authenticate action in the row menu." width="2048" height="527" data-path="assets/media/images/iru-identity-start-reauthentication-bamboo.png" />
</Frame>

<AccordionGroup>
  <Accordion title="Connection status and re-authentication" icon="plug-circle-check">
    On the **Directory → Sync** list, each connection shows whether it is
    **Enabled** or **Disabled**, plus a connection-health value:

    | Health | What it means |
    | - | - |
    | **Connected** | Iru is authorized to read from the source. |
    | **Needs re-authentication** | The credentials or the provider authorization are missing, expired, revoked, or rejected. Re-authenticate before sync can succeed. |
    | **Not connected** | The connection is not ready to authenticate (for example, setup was left incomplete). |

    On the connection's **Configuration** tab, **Connection details** shows the same
    health for that provider. Use **Re-authenticate** to enter current credentials or
    approve access with the provider again. Your attribute mapping is not affected.

    * **BambooHR:** sign in to BambooHR again in the window Iru opens, then select
      **Allow Access**.
    * **Workday:** re-enter the Integration user and password.

    <Frame caption="Re-authenticating Workday with current Integration System User credentials.">
      <img src="https://mintcdn.com/iru/60YZAZS1iNMrBv2w/assets/media/images/iru-identity-reauthenticate-workday.png?fit=max&auto=format&n=60YZAZS1iNMrBv2w&q=85&s=c79cab0ae17064cc945d1b9c482edb1b" alt="The Re-authenticate Workday dialog with Integration user and Password fields, noting that attribute mapping is not affected." width="893" height="289" data-path="assets/media/images/iru-identity-reauthenticate-workday.png" />
    </Frame>
  </Accordion>

  <Accordion title="Sync errors" icon="triangle-exclamation">
    Sync problems show up in two stages. Knowing which stage failed tells you where
    to look first.

    * **Pull-stage errors** happen when Iru cannot read from the source: bad or
      expired credentials, an expired or revoked provider authorization, an
      unreachable instance, a missing report, or a rejected API call. Fix the
      connection (often with **Re-authenticate** or by correcting the report or
      domain settings), then run sync again.
    * **Apply-stage (sync) errors** happen after Iru has the records but cannot
      create or update a particular user in your directory. Iru records a **sync
      error** you can review: when it occurred, the affected user, the action Iru
      attempted, an error code, and a message. If many records fail with the same
      error, the cause is usually a mapping: a required attribute left unmapped, or a
      unique identifier that isn't actually unique. Fix the mapping, then let the
      next sync run.

    <Frame caption="A failed sync on the Activity tab, with the full error detail. Here, a record was rejected because a required attribute was missing.">
      <img src="https://mintcdn.com/iru/yv46VZ-WbN1GdStp/assets/media/images/sync-connection-activity.webp?fit=max&auto=format&n=yv46VZ-WbN1GdStp&q=85&s=5ff12dfeabf47729bd45c799dc9cadf9" alt="The Activity tab of a connection showing a FAILED entry and an expanded error detail explaining that a user could not be provisioned because a required attribute was missing." width="1888" height="1036" data-path="assets/media/images/sync-connection-activity.webp" />
    </Frame>
  </Accordion>
</AccordionGroup>

## Related

<CardGroup cols={2}>
  <Card title="Connect Workday" icon="briefcase" href="/en/identity/directory/hris-workday">
    The Workday-specific setup, including the report step.
  </Card>

  <Card title="Connect BambooHR" icon="seedling" href="/en/identity/directory/hris-bamboohr">
    The BambooHR-specific setup.
  </Card>

  <Card title="Attribute mapping" icon="code" href="/en/identity/directory/attribute-mapping">
    The IQL you use to shape incoming values.
  </Card>

  <Card title="Schema" icon="table-list" href="/en/identity/directory/schema">
    The attributes your source fields map into.
  </Card>
</CardGroup>
