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

# API Danh mục tổ chức & vai trò

> Đọc cây đơn vị và danh sách vai trò của một tenant để map sang phòng ban, chức danh bên hệ thống nhân sự

Hai endpoint **chỉ đọc**, là bước chuẩn bị bắt buộc trước khi đồng bộ người dùng: hệ thống của bạn cần biết eContract gọi phòng ban và chức danh bằng mã nào.

| # | Endpoint                                       | Mục đích              |
| - | ---------------------------------------------- | --------------------- |
| 1 | `GET /api/integration/directory/organizations` | Cây đơn vị của tenant |
| 2 | `GET /api/integration/directory/roles`         | Vai trò của tenant    |

Toàn bộ nhóm `directory` nói bằng **mã**, không bằng id số: `code` của đơn vị và vai trò chính là giá trị bạn gửi lại ở `organizationCode` / `roleCode` khi [tạo hoặc cập nhật người dùng](/api-reference/endpoint/dong-bo-nguoi-dung).

***

## Base URL

| Môi trường  | Base URL                            |
| ----------- | ----------------------------------- |
| Production  | `https://api.econtractid.com/api`   |
| Development | `https://api-dev.epaperless.vn/api` |

***

## Xác thực

Nhóm `directory` **chỉ nhận `X-API-Key`** — không có đường đi bằng access token.

| Loại key                         | `tenantCode` | Tenant được xác định là                                         |
| -------------------------------- | ------------ | --------------------------------------------------------------- |
| **Toàn cục** (không gắn tổ chức) | **Bắt buộc** | Tổ chức có `code` trùng `tenantCode`                            |
| **Theo tổ chức**                 | Tuỳ chọn     | Tổ chức của key. Gửi `tenantCode` thì phải trùng, lệch là `403` |

```http theme={null}
GET /api/integration/directory/organizations?tenantCode=ACME
X-API-Key: econtract_a1b2c3d4e5f6...
```

<Note>
  Với key toàn cục, `tenantCode` đi ở query string (request `GET`) hoặc trong body (request `POST`/`PUT`). Cả hai đều được đọc.
</Note>

<Warning>
  `tenantCode` phải chỉ tới **đúng một** tổ chức. `organizations.code` không có ràng buộc duy nhất trên toàn hệ thống, nên khi một mã trùng ở hai tổ chức, key toàn cục nhận `400` `TENANT_CODE_AMBIGUOUS` thay vì bị gán bừa vào một tenant.
</Warning>

<Warning>
  **Đừng gắn API Key theo tổ chức vào tài khoản super admin.** Endpoint `/auth/login-server` đổi một API Key hợp lệ thành access token của tài khoản gắn key mà không cần mật khẩu — key gắn super admin vì thế là thông tin xác thực cấp toàn hệ thống, không còn giới hạn trong một tenant. Hãy gắn vào tài khoản quản trị của chính tenant đó.
</Warning>

***

## 1. Danh sách đơn vị

```http theme={null}
GET /api/integration/directory/organizations
```

### Query

| Tham số       | Kiểu      | Mặc định | Mô tả                                            |
| ------------- | --------- | -------- | ------------------------------------------------ |
| `tenantCode`  | `string`  | —        | Bắt buộc với key toàn cục                        |
| `code`        | `string`  | —        | Lọc đúng một đơn vị theo mã (khớp tuyệt đối)     |
| `parentCode`  | `string`  | —        | Chỉ lấy đơn vị con trực tiếp của đơn vị này      |
| `status`      | `integer` | —        | `1` hoạt động, `2` ngừng, `3` tạm khoá           |
| `type`        | `integer` | —        | Loại đơn vị                                      |
| `q`           | `string`  | —        | Tìm theo tên hoặc mã, không phân biệt hoa thường |
| `updatedFrom` | `string`  | —        | ISO 8601 — chỉ lấy bản ghi sửa từ mốc này trở đi |
| `updatedTo`   | `string`  | —        | ISO 8601                                         |
| `page`        | `integer` | `1`      | Trang, tính từ 1                                 |
| `pageSize`    | `integer` | `50`     | Tối đa `200`                                     |

### Response

```json theme={null}
{
  "items": [
    {
      "code": "ACME",
      "name": "Công ty ACME",
      "parentCode": null,
      "type": 1,
      "status": 1,
      "address": "12 Nguyễn Huệ, Q1",
      "phone": "02838221234"
    },
    {
      "code": "ACME-IT",
      "name": "Phòng Công nghệ thông tin",
      "parentCode": "ACME",
      "type": 1,
      "status": 1,
      "address": null,
      "phone": null
    }
  ],
  "page": 1,
  "pageSize": 50,
  "total": 2
}
```

| Trường       | Mô tả                                                                                  |
| ------------ | -------------------------------------------------------------------------------------- |
| `code`       | Mã đơn vị — giá trị dùng làm `organizationCode` khi gán người dùng                     |
| `parentCode` | Mã đơn vị cha. `null` khi đây là gốc tenant, **hoặc** khi cha nằm ngoài tenant của bạn |
| `status`     | `1` hoạt động, `2` ngừng, `3` tạm khoá. Dữ liệu cũ có thể mang giá trị khác            |

<Note>
  Kết quả luôn giới hạn trong cây tenant đã phân giải. Đơn vị của tenant khác không bao giờ xuất hiện, kể cả khi trùng mã.
</Note>

***

## 2. Danh sách vai trò

```http theme={null}
GET /api/integration/directory/roles
```

### Query

| Tham số                     | Kiểu      | Mặc định | Mô tả                                |
| --------------------------- | --------- | -------- | ------------------------------------ |
| `tenantCode`                | `string`  | —        | Bắt buộc với key toàn cục            |
| `code`                      | `string`  | —        | Lọc đúng một vai trò theo mã         |
| `organizationCode`          | `string`  | —        | Chỉ lấy vai trò thuộc đơn vị này     |
| `status`                    | `integer` | —        | Trạng thái vai trò                   |
| `isDepartmentHead`          | `boolean` | —        | `true` chỉ lấy vai trò trưởng đơn vị |
| `q`                         | `string`  | —        | Tìm theo tên hoặc mã                 |
| `updatedFrom` / `updatedTo` | `string`  | —        | ISO 8601                             |
| `page`                      | `integer` | `1`      |                                      |
| `pageSize`                  | `integer` | `50`     | Tối đa `200`                         |

### Response

```json theme={null}
{
  "items": [
    {
      "code": "NHANVIEN",
      "name": "Nhân viên",
      "organizationCode": "ACME-IT",
      "isDepartmentHead": false,
      "status": 1
    },
    {
      "code": "TRUONGPHONG",
      "name": "Trưởng phòng",
      "organizationCode": "ACME-IT",
      "isDepartmentHead": true,
      "status": 1
    }
  ],
  "page": 1,
  "pageSize": 50,
  "total": 2
}
```

<Warning>
  **`code` của vai trò thường không phân biệt được gì.** Trên dữ liệu thực tế, phần lớn vai trò dùng chung một mã mặc định (`role`) — kể cả nhiều vai trò trong cùng một đơn vị. Thứ duy nhất trong phạm vi một đơn vị là **`name`**.

  Vì vậy khi [gán người dùng](/api-reference/endpoint/dong-bo-nguoi-dung), hãy gửi `organizationCode` + **`roleName`**. Dùng `roleCode` chỉ an toàn khi tổ chức của bạn thật sự đặt mã riêng cho từng vai trò.
</Warning>

<Note>
  `organizationCode` trả về `null` khi đơn vị sở hữu vai trò đã bị xoá mềm. Vai trò vẫn được liệt kê để bạn thấy dữ liệu tồn đọng, nhưng đừng gán người dùng vào nó.
</Note>

***

## Mã lỗi

| HTTP  | `code`                         | Nguyên nhân                                                   |
| ----- | ------------------------------ | ------------------------------------------------------------- |
| `400` | `TENANT_CODE_REQUIRED`         | Dùng key toàn cục nhưng không gửi `tenantCode`                |
| `400` | `TENANT_CODE_AMBIGUOUS`        | `tenantCode` trùng ở nhiều tổ chức                            |
| `403` | `TENANT_CODE_MISMATCH`         | Key gắn tổ chức A nhưng `tenantCode` chỉ tới tổ chức B        |
| `404` | `TENANT_CODE_NOT_FOUND`        | Không có tổ chức nào mang mã đó                               |
| `404` | `ORGANIZATION_CODE_NOT_FOUND`  | `organizationCode` / `parentCode` không có trong tenant       |
| `400` | `ORGANIZATION_CODE_AMBIGUOUS`  | Mã đơn vị trùng ở nhiều bản ghi trong tenant                  |
| `401` | `API_KEY_LEGACY_NOT_SUPPORTED` | Dùng API Key kiểu cũ (lưu dạng plaintext, không thu hồi được) |

Danh sách đầy đủ: [Mã lỗi](/api-reference/ma-loi).
