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

# GET /users

> Required. Your CRM managers — the roster HunterAI attributes every lead, task, and call to. Fetched in full on every sync, not incremental.

<Info>
  **Required.** `/users` returns your managers — the people who own leads, tasks,
  and calls. It is **not** [incremental](/concepts/how-sync-works#incremental-sync):
  it is fetched in full on every sync.
</Info>

## Purpose

A user is one manager in your CRM — a person who owns work. HunterAI reads
`/users` to build the manager roster and to resolve per-manager attribution:
every lead, task, and call points at a user through `responsible_user_id`, and
that link is what powers per-manager analytics. `is_active` separates current
managers from ones who have left, so departed managers can be excluded from
live reporting without losing their history.

## Request

`/users` is **not incremental** — it receives no `updated_since` and is fetched in
full on every sync. Return your complete current list each time.

```http theme={null}
GET /api/hunterai/v1/users?limit=100&page=1 HTTP/1.1
Host: crm.example.uz
Authorization: Bearer <token>
Accept: application/json
```

| Query param | Value       | Notes                                               |
| ----------- | ----------- | --------------------------------------------------- |
| `limit`     | `100`       | Always sent. Return up to this many users per page. |
| `page`      | `1`, `2`, … | 1-based. Page until `has_more` is `false`.          |

## Response envelope

```json 200 OK theme={null}
{
  "data": [
    { "id": "u-1001", "name": "Aziz Karimov",    "email": "aziz@example.uz",    "role": "manager", "is_active": true },
    { "id": "u-1002", "name": "Dilnoza Yusupova", "email": "dilnoza@example.uz", "role": "head",    "is_active": true },
    { "id": "u-1003", "name": "Rustam Sobirov",   "email": "rustam@example.uz",  "role": "manager", "is_active": false }
  ],
  "has_more": false,
  "page": 1,
  "limit": 100
}
```

The envelope (`data`, `has_more`, `page`, `limit`) is the same on every endpoint
— see [How sync works → The envelope](/concepts/how-sync-works#the-envelope).
Only `data` and `has_more` are read.

## Fields

| Field       | Type    | Required | Nullable | Format / Constraint                                                              | Example             | Notes                                                                                                                                               |
| ----------- | ------- | -------- | -------- | -------------------------------------------------------------------------------- | ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
| `id`        | string  | Yes      | No       | max 255 chars; stable and unique per connection; never changes for the same user | `"u-1001"`          | The upsert key together with the connection. An absent or over-length `id` fails its page.                                                          |
| `name`      | string  | No       | Yes      | max 255 chars                                                                    | `"Aziz Karimov"`    | Display name. Silently truncated to 255 chars.                                                                                                      |
| `email`     | string  | No       | Yes      | max 255 chars                                                                    | `"aziz@example.uz"` | Stored as-is. Silently truncated to 255 chars.                                                                                                      |
| `role`      | string  | No       | Yes      | max 100 chars                                                                    | `"manager"`         | Free-text role label — any string you use in your CRM (e.g. `"manager"`, `"head"`). Not validated against a list. Silently truncated to 100 chars.  |
| `is_active` | boolean | No       | No       | `true` or `false`                                                                | `true`              | Whether the manager is currently active. Defaults to `true` when the key is omitted; an explicit `null` is stored as `false`. Never stored as null. |

### Timestamp format

This endpoint reads **no timestamp fields**. `/users` is fetched in full every
sync and is not watermarked, so any `created_at` or `updated_at` you send on a
user is ignored.

## Fields the adapter ignores

Sending any of these has **no effect** — do not spend effort populating them:

* `phone` — dropped. There is no phone column on a user, so a `phone` you send is
  discarded. See [Limitations → Fields dropped entirely](/limitations#fields-dropped-entirely).
* Any `created_at` / `updated_at` — `/users` is not incremental, so timestamps
  here are not read.
* Any other key not listed in the [Fields](#fields) table — users retain no raw
  copy, so anything unlisted is dropped entirely.

## Identity & cross-references

* **Identity:** `id` is the stable primary key. HunterAI upserts by
  `(connection, id)`, so a user's `id` **must never change** — a changed `id` is
  ingested as a brand-new user, orphaning every deal, task, and call that pointed
  at the old one.
* **Referenced by other entities:** each `responsible_user_id` on
  [`/leads`](/endpoints/leads), [`/contacts`](/endpoints/contacts),
  [`/tasks`](/endpoints/tasks), and [`/calls`](/endpoints/calls) resolves to a
  user `id` returned here. Return every user any of those entities can reference,
  or their attribution is left unresolved.
* `/users` itself points at no other entity.

## Incremental sync

**This endpoint is not incremental.** `/users` receives no `updated_since` and is
fetched in full on every sync — return your complete current list of managers
every time. This collection is expected to be small (tens to low hundreds of
rows). See
[How sync works → Incremental sync](/concepts/how-sync-works#incremental-sync).

## Deletion behaviour

Users have **no tombstone** — there is no `is_deleted` on a user. Because the
upsert only inserts and updates, a user you remove from your response is **not**
deleted from HunterAI; it simply stops being refreshed and the historical row
persists. To mark a manager as gone, set `is_active: false` rather than dropping
them from the response — that keeps their past attribution while excluding them
from live reporting. Only leads support deletion, via `is_deleted` — see
[Limitations → Tombstones](/limitations#tombstones-apply-to-leads-only).

## Failure modes

A page of users (up to 100 records) is validated and written **as one
transaction**. The consequences:

* **A single malformed user fails the whole page.** If any user on a page cannot
  be processed — a missing `id`, or an over-length `id` — none of the users on
  that page are saved. This is page-level, not per-record.
* **A failed page fails the sync.** Because `/users` is required, a page that
  fails takes the users entity down with it, and the overall sync is reported
  *failed*. Pages that already committed stay committed.
* **`429`, `5xx`, and request timeouts** are retried with exponential backoff up
  to 5 times, then the entity fails; a timeout is retried the same way as a
  `5xx`. HunterAI applies its request rate limit **per connection**, so two
  connections to the same base URL are throttled independently.
* **A repeated or unbounded page** — a page whose IDs match the previous page, or
  a run past the page ceiling — fails the entity. See
  [How sync works → Paging](/concepts/how-sync-works#paging).

## If this endpoint is missing

<Warning>
  `/users` is **required**. A `404` fails the users entity and the sync is
  reported failed. Without the roster, every `responsible_user_id` on a lead,
  task, or call resolves to nobody, so per-manager attribution is empty across
  the product.
</Warning>
