# Poll Leaver Items Nightly
URL: https://docs.autociso.io/api/poll-offboarding/
Description: A copy-paste recipe that reads leaver items still outstanding or in discrepancy every night, de-duplicates them by itemKey, and hands only new ones to your ticketing tool.

**Goal:** every morning, get a short list of leaver access that still needs a person — and open a ticket for each new item once, not every day.

**You need:** an organisation [Owner or Manager](https://docs.autociso.io/getting-started/roles-and-permissions/) to create a token, a
[plan](https://docs.autociso.io/getting-started/plans-and-features/) that includes Employee lifecycle, and a small server-side job (cron, a CI schedule, a workflow tool). About ten minutes.

## 1. Create a token for the job

1. Open the user menu → [**API Tokens**](https://docs.autociso.io/console/settings/api-tokens/) and click **Create Token**.
2. Name it after the job, for example `nightly-leaver-poll`.
3. Under **Employee lifecycle**, tick **jml:read — Read joiner/leaver status**. Leave **Employee identity (pii:read)** off unless your ticket needs a person's name; without it you get employee IDs and masked emails, which is enough to route a ticket.
4. Keep the expiry the dialog preselects (**90 days**) and click **Create Token**.
5. Copy the token from the **Token Created** dialog into your secrets manager. It is shown once.

**Warning — Keep the token on the server**

Send it only in the `Authorization: Bearer` header from your job. Do not put it in a URL, a browser, a chat message or the ticket text. If you serve several client organisations, each client creates its own token — see [API tokens](https://docs.autociso.io/developers/api-tokens/#handle-tokens-safely).

## 2. Ask for what needs attention

The leaver items feed ([List leaver items](https://docs.autociso.io/api/reference/offboarding-items/list/)) returns one row per leaver item across all your cases. Filter it to the two statuses that need a person: `OUTSTANDING` (access still there, nobody claims to have removed it) and `DISCREPANCY` (marked done, but the access is still detected):

```bash
export AUTOCISO_API_TOKEN="aci_<redacted>"   # load it from your secrets manager

curl -s -G \
  -H "Authorization: Bearer $AUTOCISO_API_TOKEN" \
  --data-urlencode "filter[status][in]=OUTSTANDING,DISCREPANCY" \
  --data-urlencode "filter[caseStatus][in]=OPEN,IN_PROGRESS" \
  --data-urlencode "sort[openedAt]=desc" \
  --data-urlencode "limit=100" \
  "https://api.autociso.io/api/v1/jml/offboarding/items"
```

The response is `{ data, error, meta }`. `meta.total` is how many items match and `meta.summary` counts them per status. Each item has `status`, `assetName`, `employeeId`, `caseId` and the stable key `itemKey`.

## 3. Page through the results

`limit` is at most 100. Repeat the call with `offset=100`, `offset=200` and so on until you have read `meta.total` items:

```bash
offset=0
while :; do
  page=$(curl -s -G -H "Authorization: Bearer $AUTOCISO_API_TOKEN" \
    --data-urlencode "filter[status][in]=OUTSTANDING,DISCREPANCY" \
    --data-urlencode "limit=100" --data-urlencode "offset=$offset" \
    "https://api.autociso.io/api/v1/jml/offboarding/items")
  echo "$page" | jq -c '.data[]' >> today.jsonl
  total=$(echo "$page" | jq '.meta.total')
  offset=$((offset + 100))
  [ "$offset" -ge "$total" ] && break
done
```

For a small company this is one page. Do not call the case endpoints once per case; the feed exists so you do not have to.

## 4. Open a ticket only for new items

Keep the `itemKey` values you have already handled — a file, a database table or a label on the ticket. For each item today:

- Its `itemKey` is new: open a ticket. For `DISCREPANCY`, write "Marked done, but the access is still detected. Check it first." For `OUTSTANDING`, write "Access is still active. Remove it in the source system."
- Its `itemKey` is known but the `status` changed (for example `OUTSTANDING` to `DISCREPANCY`): update the existing ticket.
- A key you handled before is missing from today's list: the access is now revoked, or the case was closed. Close the ticket.

`itemKey` does not change when the asset is renamed or deleted, so it is safe to store.

## 5. Handle errors and limits

| Response | What to do |
|----------|------------|
| `429 RATE_LIMITED` | Read the `Retry-After` header (seconds), wait that long, retry once. A nightly job rarely sees this. |
| `422 QUERY_TOO_BROAD` | The result set is larger than the server will return in one go. Add `filter[openedAt][gte]` (for example the last 90 days) or filter by `filter[caseStatus][in]` and run it again. |
| `503` | A dependency is briefly unavailable. Retry after a few minutes; if it persists, quote `error.id` to support. |
| `401 INVALID_TOKEN` | The token expired or was revoked. Create a new one before the expiry date — the token list shows **Expires in N days** — and swap it in. |
| `402 FEATURE_GATED` | Your plan does not include Employee lifecycle. |

Every other code is explained in [Errors & rate limits](https://docs.autociso.io/developers/errors-and-limits/).

## 6. Schedule it

Run it once a day, after your access data normally refreshes:

```cron
0 6 * * *  /opt/jobs/leaver-poll.sh
```

**Note — Do not read the timestamps as a scan time**

`meta.accessDataAsOf` is the newest time AutoCISO detected any of the access it used; it is **not** the time of a scan. If it is days old, an application is probably not connected or not scanned — and a leaver's access in it will not show as revoked until it is. In the console the same value appears as **Latest detection**.

## What you are looking at

These are **Leaver case items** — the items of leaver cases in the console, under **Lifecycle (JML)**, tab [**Leaver (Offboarding)**](https://docs.autociso.io/console/operations/offboarding/). Terminated employees who still have access but no leaver case appear in [Offboarding violations](https://docs.autociso.io/console/ciso-reports/offboarding-violations/), the CISO report, and the `access_offboarding_violations` MCP tool, not here. The product page [Offboarding](https://docs.autociso.io/product/lifecycle/offboarding/) guide explains the difference.

## Next steps

- [List leaver items](https://docs.autociso.io/api/reference/offboarding-items/list/) — statuses, filters, personal-data rules, rate limits
- [Leaver cases](https://docs.autociso.io/api/reference/offboarding-cases/list/) — the same data case by case
- [API Quickstart](https://docs.autociso.io/api/quickstart/)
