# List the items of a leaver case

Lists the reconciled items of one leaver case.

`GET /jml/offboarding/cases/{caseId}/items`

Scope `jml:read` | Plan **Seed+**

Lists the reconciled items of one leaver case. meta.summary counts the whole filtered set before pagination.

## Path parameters

| Name | Type | Required | Description |
|---|---|---|---|
| `caseId` | string | yes | Leaver case id (lfc_...). An unknown, foreign or malformed id returns the same 404. pattern `^lfc_[A-Za-z0-9_-]{1,59}$` |

## Query parameters

| Name | Type | Required | Description |
|---|---|---|---|
| `limit` | integer | no | Page size. Default 25, maximum 100; a larger value is rejected with 400 VALIDATION_FAILED. minimum 1, maximum 100, default 25 |
| `offset` | integer | no | Zero-based offset. Maximum 100000. minimum 0, maximum 100000, default 0 |
| `filter[status][eq]` | string | no | Reconciled item status. One of `REVOKED`, `OUTSTANDING`, `DISCREPANCY`, `ATTESTED`. |
| `filter[status][ne]` | string | no | One of `REVOKED`, `OUTSTANDING`, `DISCREPANCY`, `ATTESTED`. |
| `filter[status][in]` | array of string | no | maxItems 100 Each one of `REVOKED`, `OUTSTANDING`, `DISCREPANCY`, `ATTESTED`. |

## Returns

The `data` field of the standard `{ data, error, meta }` envelope:

An array of object:
- `itemId`: string
- `itemKey`: string Stable key for deduplicating items across polls: caseId:assetId for an item tied to an application, caseId:taskId for a manual step. It does not change if the asset is later deleted.
- `taskId`: string or null Null for ACCESS_ONLY items.
- `caseId`: string
- `employeeId`: string
- `assetId`: string or null Null for MANUAL_TASK items. Older assets may carry a 24-character hex asset id.
- `assetName`: string or null Null when the asset no longer exists or the item is manual.
- `status`: string Reconciled each time you read it, from the task status and the access inventory. REVOKED: the inventory shows the access is gone (a stale pending task can still be present; taskStatus tells you); nothing to do. OUTSTANDING: the access is still active and nobody has marked it done, or it is a manual step that is not done; also used for access detected after the case was opened. Remove the access, then wait for the next access scan. DISCREPANCY: someone marked the task done but the access is still detected (a failed removal, a re-provisioned account or stale data). Check it first. ATTESTED: a person marked the item done in the console and the access is not detected; neither verified nor contradicted.
  - `REVOKED`
  - `OUTSTANDING`
  - `DISCREPANCY`
  - `ATTESTED`
- `taskStatus`: string or null Null for ACCESS_ONLY items.
- `accessStatus`: string or null Null when no access record exists.
- `source`: string TASK: a task on the case. ACCESS_ONLY: access detected with no task; it is attached to the leaver's most recent case. MANUAL_TASK: a step that is not tied to an application.
  - `TASK`
  - `ACCESS_ONLY`
  - `MANUAL_TASK`
- `openedAt`: string (date-time) Opening time of the owning case.
- `taskCompletedAt`: string (date-time) or null When a person marked the task done. There is no "revoked at" field, because access detection time is not a scan time; use this field.
- `accessLastDetectedAt`: string (date-time) or null

The `meta` field:

- `limit`: integer
- `offset`: integer
- `total`: integer
- `summary`: object Counts of leaver items per reconciled status. total is the sum of the four.
  - `total`: integer minimum 0
  - `revoked`: integer minimum 0
  - `outstanding`: integer minimum 0
  - `discrepancy`: integer minimum 0
  - `attested`: integer minimum 0
- `accessDataAsOf`: string (date-time) or null Latest access detection time used for this response.

## Errors

| Status | Code | Retry | Meaning |
|---|---|---|---|
| 400 | `VALIDATION_FAILED` | no | Invalid query parameter. code VALIDATION_FAILED; args.parameter names the parameter, args.reason the rule, args.allowed the permitted values of an enum. |
| 401 | `INVALID_TOKEN` | no | Missing (UNAUTHORIZED) or invalid, expired or revoked (INVALID_TOKEN) token. |
| 402 | `FEATURE_GATED` | no | The tenant plan does not include lifecycle workflows. code FEATURE_GATED; args.feature, args.minTier, args.minTierName. |
| 403 | `INSUFFICIENT_SCOPE` | no | The token lacks the jml:read scope (INSUFFICIENT_SCOPE; a token holding pii:read alone reaches no endpoint here), or the request is refused (FORBIDDEN). A token holding pii:read is also refused with INSUFFICIENT_SCOPE when personal data cannot be disclosed to it (personal-data disclosure is disabled for the tenant, or the token has no creator); it is never silently downgraded to the masked shape. |
| 404 | `NOT_FOUND` | no | Unknown, foreign-tenant, wrong-type or malformed case id. Always the same body. |
| 429 | `RATE_LIMITED` | yes | Rate limit exceeded. code RATE_LIMITED; wait Retry-After seconds. Applies to the personal-data (pii:read) request window on case endpoints, where Retry-After is the time until the window ends. That window is shared by all calls of the token, over REST and MCP; a request that fails with 503 AUDIT_UNAVAILABLE is not refunded, so retrying spends more of it. Do not build a design that depends on an exact number of requests. It also applies to concurrent feed requests on the items feeds, where Retry-After is 1. The body carries no meta. |
| 500 | `INTERNAL_ERROR` | no | Unexpected server error. code INTERNAL_ERROR; quote error.id to support. |
| 503 | `BILLING_UNAVAILABLE` | yes | A dependency is temporarily unavailable (BILLING_UNAVAILABLE), or a response containing name or email could not be audited and was withheld (AUDIT_UNAVAILABLE). Retry later. |

## Example

### curl

```bash
curl "https://api.autociso.io/api/v1/jml/offboarding/cases/<caseId>/items" \
  -H "Authorization: Bearer <your-api-token>"
```

### Python

```python
import requests

response = requests.get(
    "https://api.autociso.io/api/v1/jml/offboarding/cases/<caseId>/items",
    headers={"Authorization": "Bearer <your-api-token>"},
)
print(response.json())
```

### JavaScript

```javascript
const response = await fetch("https://api.autociso.io/api/v1/jml/offboarding/cases/<caseId>/items", {
  method: "GET",
  headers: { "Authorization": "Bearer <your-api-token>" },
});
console.log(await response.json());
```

## Response (200)

```json
{
  "data": [
    {
      "itemId": "ltsk_example000001",
      "itemKey": "lfc_example000001:ast_example000001",
      "taskId": "ltsk_example000001",
      "caseId": "lfc_example000001",
      "employeeId": "empl_example000001",
      "assetId": "ast_example000001",
      "assetName": "Example CRM",
      "status": "DISCREPANCY",
      "taskStatus": "COMPLETED",
      "accessStatus": "ACTIVE",
      "source": "TASK",
      "openedAt": "2026-09-15T08:00:00Z",
      "taskCompletedAt": "2026-09-16T10:30:00Z",
      "accessLastDetectedAt": "2026-09-29T02:00:00Z"
    }
  ],
  "error": null,
  "meta": {
    "limit": 25,
    "offset": 0,
    "total": 1,
    "summary": {
      "total": 1,
      "revoked": 0,
      "outstanding": 0,
      "discrepancy": 1,
      "attested": 0
    },
    "accessDataAsOf": "2026-09-29T02:00:00Z"
  }
}
```
