> ## 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 Công việc ký

> Danh sách hồ sơ cần ký / đã ký, chi tiết một công việc, và lịch sử phê duyệt của hồ sơ

Ba endpoint xoay quanh **công việc ký của một người dùng** và **vết phê duyệt** của hồ sơ.

| # | Endpoint                                              | Mục đích                       |
| - | ----------------------------------------------------- | ------------------------------ |
| 1 | `GET /api/integration/tasks`                          | Danh sách hồ sơ cần ký / đã ký |
| 2 | `GET /api/integration/tasks/{taskCode}`               | Chi tiết một công việc         |
| 3 | `GET /api/integration/documents/{documentId}/history` | Lịch sử phê duyệt của hồ sơ    |

***

## Base URL

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

***

## Header

Cả ba endpoint chấp nhận **hai cách xác thực**, chọn một:

| Header                          | Dùng khi                                     | Người dùng được xác định là   |
| ------------------------------- | -------------------------------------------- | ----------------------------- |
| `X-API-Key: econtract_...`      | Backend của bạn gọi server-to-server         | Tài khoản **gắn với API Key** |
| `x-access-token: eyJhbGciOi...` | Ứng dụng/iframe gọi thay cho người dùng cuối | Chủ sở hữu access token       |

```http theme={null}
GET /api/integration/tasks
X-API-Key: econtract_a1b2c3d4e5f6...
```

<Warning>
  **API Key phải resolve được người dùng.** Key chưa gắn tài khoản → `401` với message *API key chưa gắn người dùng*; tài khoản đã bị vô hiệu hoá → `401` *Tài khoản dịch vụ không hoạt động*. Xem [Xác thực](/api-reference/xac-thuc).

  API Key trả về công việc của **chính tài khoản gắn với key**. Muốn lấy danh sách theo từng người ký, dùng access token của người đó (lấy qua [partner-login](/api-reference/xac-thuc)).
</Warning>

<Note>
  Access token đi ở header `x-access-token`, **không** phải `Authorization: Bearer`. Gửi đồng thời cả hai header thì `X-API-Key` được ưu tiên.
</Note>

***

## 1. Danh sách công việc ký

```http theme={null}
GET /api/integration/tasks
```

### Body

Không có. Đây là request `GET`, mọi tham số truyền qua query string.

### Query

| Tham số      | Kiểu      | Mặc định   | Mô tả                                                                      |
| ------------ | --------- | ---------- | -------------------------------------------------------------------------- |
| `status`     | `enum`    | *(tất cả)* | Xem bảng giá trị ngay dưới. Bỏ trống = `all`                               |
| `page`       | `integer` | `1`        | Trang, tính từ 1                                                           |
| `pageSize`   | `integer` | `20`       | Số bản ghi mỗi trang, tối đa `100`                                         |
| `fromDate`   | `string`  | —          | ISO 8601. `pending` lọc theo `assignedAt`; `completed` lọc theo `actionAt` |
| `toDate`     | `string`  | —          | ISO 8601, cùng quy tắc với `fromDate`                                      |
| `documentId` | `string`  | —          | Lọc đúng một hồ sơ theo mã hồ sơ bạn cấp khi tạo                           |
| `keyword`    | `string`  | —          | Tìm toàn văn theo tên hồ sơ và tên bước ký                                 |

#### Giá trị của `status`

Giá trị là bản viết thường của `items[].status`, cộng hai giá trị gộp:

| Giá trị            | Trả về                                          |
| ------------------ | ----------------------------------------------- |
| `pending`          | Công việc **đang chờ** người dùng xử lý         |
| `approved`         | Công việc người dùng **đã ký / đã duyệt**       |
| `rejected`         | Công việc người dùng **đã từ chối**             |
| `expired`          | Công việc người dùng **để quá hạn**             |
| `completed`        | Gộp `approved` + `rejected` + `expired`         |
| `all` *(mặc định)* | Tất cả, trộn và sắp xếp theo thời gian giảm dần |

Các tập con cộng lại đúng bằng tập cha: `approved + rejected + expired = completed`, và `pending + completed = all`.

```bash theme={null}
# Cả cần ký lẫn đã ký
curl -sS -H "X-API-Key: econtract_a1b2c3d4..." \
  "https://api.econtractid.com/api/integration/tasks?page=1&pageSize=20"

# Chỉ hồ sơ cần ký
curl -sS -H "X-API-Key: econtract_a1b2c3d4..." \
  "https://api.econtractid.com/api/integration/tasks?status=pending"

# Chỉ hồ sơ đã ký (bỏ qua từ chối và quá hạn)
curl -sS -H "X-API-Key: econtract_a1b2c3d4..." \
  "https://api.econtractid.com/api/integration/tasks?status=approved"
```

<Note>
  Tham số không nằm trong bảng trên bị **bỏ qua**, không báo lỗi.
</Note>

### Response

```json theme={null}
{
  "statusCode": 200,
  "data": {
    "items": [
      {
        "taskId": 2476,
        "taskCode": "TI000123",
        "stepCode": "customer",
        "stepName": "Khách hàng ký",
        "signType": "digital_signature",
        "status": "PENDING",
        "assignedAt": "2026-07-10T04:50:12.000Z",
        "expireAt": "2026-07-17T04:50:12.000Z",
        "document": {
          "folderId": 12345,
          "documentId": "HD-2026-001",
          "documentUuid": "8d5e7b2a-1c4f-4a3b-9d6e-2f8c7a1e5b9d",
          "documentTitle": "Hợp đồng dịch vụ — Nguyễn Văn A",
          "transactionId": "PI000042",
          "ecmClassCode": "Tai-lieu-hop-dong-lao-dong",
          "status": "PENDING_SIGN",
          "requiredCount": 2,
          "signedCount": 0,
          "createdAt": "2026-07-10T04:50:00.000Z"
        }
      }
    ],
    "page": 1,
    "pageSize": 20,
    "total": 1
  },
  "timestamp": "2026-07-10T05:00:00.000Z"
}
```

#### Trường cấp `data`

| Trường     | Kiểu      | Mô tả                                                       |
| ---------- | --------- | ----------------------------------------------------------- |
| `items[]`  | `array`   | Danh sách công việc, xem bảng dưới                          |
| `page`     | `integer` | Trang hiện tại (echo lại query)                             |
| `pageSize` | `integer` | Kích thước trang (echo lại query)                           |
| `total`    | `integer` | Tổng số bản ghi khớp bộ lọc, **không** phụ thuộc phân trang |

#### Trường của `items[]`

| Trường       | Kiểu      | Mô tả                                                                                                                      |
| ------------ | --------- | -------------------------------------------------------------------------------------------------------------------------- |
| `taskId`     | `integer` | ID số của công việc. Dùng dựng **deeplink mở giao diện econtractid**: `/tasks?id={taskId}` (nhúng iframe hoặc SDK)         |
| `taskCode`   | `string`  | **Định danh công việc** (vd `TI000123`). Dùng làm path param cho endpoint chi tiết                                         |
| `stepCode`   | `string`  | Mã bước ký trong quy trình — chính là `stepCode` bạn gửi khi tạo hồ sơ                                                     |
| `stepName`   | `string`  | Tên hiển thị của bước ký                                                                                                   |
| `signType`   | `string`  | Hình thức ký cấu hình ở bước: `digital_signature`, `image_signature`, `app_submit`, `notification`                         |
| `status`     | `enum`    | `PENDING` (chờ xử lý) · `APPROVED` (đã ký/duyệt) · `REJECTED` (đã từ chối) · `EXPIRED` (quá hạn). Xem bảng suy ra bên dưới |
| `assignedAt` | `string`  | Thời điểm công việc được giao (ISO 8601)                                                                                   |
| `expireAt`   | `string`  | Hạn xử lý (ISO 8601). Vắng mặt nếu bước không đặt hạn                                                                      |
| `actionAt`   | `string`  | Thời điểm người dùng ký/từ chối. Chỉ có ở bản ghi đã xử lý                                                                 |
| `comment`    | `string`  | Ý kiến người dùng nhập khi ký hoặc từ chối                                                                                 |
| `document`   | `object`  | Hồ sơ chứa công việc này, xem bảng dưới                                                                                    |

#### Trường của `items[].document`

| Trường          | Kiểu      | Mô tả                                                                                                                                                                  |
| --------------- | --------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `folderId`      | `integer` | ID số của hồ sơ (= `folderId` ở API tạo hồ sơ). Deeplink: `/folders?id={folderId}`                                                                                     |
| `documentId`    | `string`  | Mã hồ sơ **bạn cấp** khi tạo — khớp với `documentId` ở các endpoint khác. **Rỗng** nếu hồ sơ không được tạo qua Integration API (vd người dùng tạo trực tiếp trên web) |
| `documentUuid`  | `string`  | UUID công khai của hồ sơ, bất biến                                                                                                                                     |
| `documentTitle` | `string`  | Tên hiển thị của hồ sơ                                                                                                                                                 |
| `transactionId` | `string`  | Mã tiến trình quy trình (vd `PI000042`)                                                                                                                                |
| `ecmClassCode`  | `string`  | Phân loại hồ sơ                                                                                                                                                        |
| `status`        | `enum`    | Trạng thái hồ sơ — cùng thang giá trị với [tra cứu hồ sơ](/api-reference/endpoint/ho-so): `PENDING`, `PENDING_SIGN`, `IN_PROGRESS`, `COMPLETED`, `REJECTED`, `EXPIRED` |
| `requiredCount` | `integer` | Tổng số bước ký của hồ sơ                                                                                                                                              |
| `signedCount`   | `integer` | Số bước ký đã hoàn tất                                                                                                                                                 |
| `createdAt`     | `string`  | Thời điểm tạo hồ sơ (ISO 8601)                                                                                                                                         |

#### `items[].status` được suy ra từ đâu

| Nguồn                                                                                    | Giá trị DB | `status` trả về |
| ---------------------------------------------------------------------------------------- | ---------- | --------------- |
| Hành động đã thực hiện (`task_history.action_code`)                                      | `NEXT`     | `APPROVED`      |
|                                                                                          | `REJECT`   | `REJECTED`      |
|                                                                                          | `OVERDUE`  | `EXPIRED`       |
| Trạng thái công việc (`process_tasks.status`) — khi chưa có hành động nào của người dùng | `1` (chờ)  | `PENDING`       |
|                                                                                          | `2`        | `APPROVED`      |
|                                                                                          | `3`        | `REJECTED`      |
|                                                                                          | `4`        | `EXPIRED`       |

Hành động được ưu tiên hơn trạng thái công việc: một bước có thể đã bị đóng bởi bước sau, nhưng lượt xử lý của bạn vẫn phải phản ánh đúng việc bạn đã làm.

<Note>
  Danh sách trả về **mọi** công việc của người dùng, kể cả hồ sơ do người dùng tạo trực tiếp trên web. Những hồ sơ đó không có mã bạn cấp nên `document.documentId` rỗng — hãy dùng `document.documentUuid` làm định danh ổn định trong trường hợp này.
</Note>

<Note>
  Trường không có giá trị được **lược khỏi JSON**, không trả `null`. Ví dụ hồ sơ chờ ký sẽ không có `actionAt` và `comment`; bước không đặt hạn sẽ không có `expireAt`.
</Note>

#### Khác biệt giữa hai loại bản ghi

|                              | Chờ xử lý                                 | Đã xử lý                                         |
| ---------------------------- | ----------------------------------------- | ------------------------------------------------ |
| Nguồn                        | Công việc đang chờ, thuộc hồ sơ đang chạy | Mỗi lượt người dùng đã ký / từ chối / để quá hạn |
| `items[].status`             | `PENDING`                                 | `APPROVED` · `REJECTED` · `EXPIRED`              |
| `actionAt`                   | Không có                                  | Luôn có                                          |
| Lọc `fromDate`/`toDate` theo | `assignedAt`                              | `actionAt`                                       |

Khi `status` bỏ trống, hai loại được trộn và sắp xếp theo thời gian giảm dần (`actionAt` nếu đã xử lý, `assignedAt` nếu đang chờ).

<Note>
  Một công việc có thể xuất hiện **hai lần** khi bạn lấy cả hai loại: bước có nhiều người ký, bạn đã ký phần mình (bản ghi `APPROVED`) nhưng bước vẫn đang chờ người còn lại (bản ghi `PENDING`). Đây là hai sự kiện khác nhau, không phải trùng lặp.
</Note>

***

## 2. Chi tiết một công việc

```http theme={null}
GET /api/integration/tasks/{taskCode}
```

`taskCode` lấy từ `items[].taskCode` của endpoint danh sách.

Trả về **toàn bộ trường của một item** trong danh sách, kèm ba nhóm bổ sung: `assignee`, `files`/`attachments`, và `history`.

```json theme={null}
{
  "statusCode": 200,
  "data": {
    "taskId": 2476,
    "taskCode": "TI000123",
    "stepCode": "customer",
    "stepName": "Khách hàng ký",
    "signType": "digital_signature",
    "status": "APPROVED",
    "assignedAt": "2026-07-10T04:50:12.000Z",
    "expireAt": "2026-07-17T04:50:12.000Z",
    "actionAt": "2026-07-10T04:53:51.644Z",
    "comment": "Đồng ý các điều khoản",
    "assignee": {
      "email": "a@x.com",
      "phone": "0909123001",
      "identityNumber": "079209876543"
    },
    "document": {
      "folderId": 12345,
      "documentId": "HD-2026-001",
      "documentUuid": "8d5e7b2a-1c4f-4a3b-9d6e-2f8c7a1e5b9d",
      "documentTitle": "Hợp đồng dịch vụ — Nguyễn Văn A",
      "transactionId": "PI000042",
      "ecmClassCode": "Tai-lieu-hop-dong-lao-dong",
      "status": "IN_PROGRESS",
      "requiredCount": 2,
      "signedCount": 1,
      "createdAt": "2026-07-10T04:50:00.000Z"
    },
    "files": [
      {
        "id": 678,
        "fileUuid": "f1a2b3c4-...",
        "title": "Hợp đồng",
        "type": "MAIN",
        "url": "https://minio.../f1a2b3c4.pdf?X-Amz-Signature=...",
        "downloadUrl": "/api/integration/files/f1a2b3c4-.../download",
        "ecmClassCode": "Tai-lieu-hop-dong-lao-dong",
        "size": 234567,
        "mimeType": "application/pdf"
      }
    ],
    "attachments": [],
    "history": [
      {
        "taskId": 2476,
        "taskCode": "TI000123",
        "stepCode": "customer",
        "stepName": "Khách hàng ký",
        "action": "NEXT",
        "actionLabel": "Ký duyệt",
        "actionAt": "2026-07-10T04:53:51.644Z",
        "comment": "Đồng ý các điều khoản",
        "actorName": "Nguyễn Văn A",
        "actorEmail": "a@x.com"
      }
    ]
  },
  "timestamp": "2026-07-10T05:00:00.000Z"
}
```

### Trường bổ sung

| Trường          | Kiểu     | Mô tả                                                                                                                                                                                                                    |
| --------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `assignee`      | `object` | Người phải xử lý bước. Chỉ chứa các trường ứng với loại bước: khách mời → `email`/`phone`/`identityNumber`/`taxCode`; nhân sự nội bộ → `username`/`name`/`email`/`phone`; bước theo vai trò → thêm `roleCode`/`roleName` |
| `files[]`       | `array`  | File chính của hồ sơ — **cùng cấu trúc** với [liệt kê file](/api-reference/endpoint/ho-so)                                                                                                                               |
| `attachments[]` | `array`  | File đính kèm, không tham gia ký                                                                                                                                                                                         |
| `history[]`     | `array`  | Lịch sử thao tác của **riêng công việc này**, xem bảng ở mục 3                                                                                                                                                           |

<Note>
  `username` và `roleCode`/`roleName` **chỉ trả với bước ký bằng tài khoản nội bộ**. Với khách mời, username hệ thống chính là CCCD/MST nên không được trả ra, tránh lộ định danh cá nhân qua trường sai ngữ nghĩa.
</Note>

### Lỗi

| HTTP  | Nguyên nhân                                                                                             |
| ----- | ------------------------------------------------------------------------------------------------------- |
| `404` | `taskCode` không tồn tại, hoặc nằm ngoài phạm vi đọc của bạn (gộp hai trường hợp — không lộ sự tồn tại) |

***

## 3. Lịch sử phê duyệt của hồ sơ

```http theme={null}
GET /api/integration/documents/{documentId}/history
```

Toàn bộ vết phê duyệt của hồ sơ — mọi bước, mọi người ký — sắp xếp theo **thời gian tăng dần**, đọc từ trên xuống là đúng trình tự.

```json theme={null}
{
  "statusCode": 200,
  "data": {
    "folderId": 12345,
    "documentId": "HD-2026-001",
    "documentUuid": "8d5e7b2a-1c4f-4a3b-9d6e-2f8c7a1e5b9d",
    "documentTitle": "Hợp đồng dịch vụ — Nguyễn Văn A",
    "transactionId": "PI000042",
    "status": "COMPLETED",
    "requiredCount": 2,
    "signedCount": 2,
    "history": [
      {
        "taskId": 2476,
        "taskCode": "TI000123",
        "stepCode": "customer",
        "stepName": "Khách hàng ký",
        "action": "NEXT",
        "actionLabel": "Ký duyệt",
        "actionAt": "2026-07-10T04:53:51.644Z",
        "comment": "Đồng ý các điều khoản",
        "actorName": "Nguyễn Văn A",
        "actorEmail": "a@x.com"
      },
      {
        "taskId": 2477,
        "taskCode": "TI000124",
        "stepCode": "internal_user",
        "stepName": "Nhân sự nội bộ ký",
        "action": "NEXT",
        "actionAt": "2026-07-10T04:55:36.327Z",
        "actorName": "Nguyễn Thành Long",
        "actorUsername": "longnt"
      }
    ]
  },
  "timestamp": "2026-07-10T05:00:00.000Z"
}
```

### Trường của `history[]`

| Trường                      | Kiểu      | Mô tả                                                        |
| --------------------------- | --------- | ------------------------------------------------------------ |
| `taskId`                    | `integer` | ID số của công việc — deeplink `/tasks?id={taskId}`          |
| `taskCode`                  | `string`  | Mã công việc tương ứng — dùng để gọi endpoint chi tiết       |
| `stepCode`                  | `string`  | Mã bước ký                                                   |
| `stepName`                  | `string`  | Tên bước ký                                                  |
| `action`                    | `enum`    | `NEXT` (ký/duyệt) · `REJECT` (từ chối) · `OVERDUE` (quá hạn) |
| `actionLabel`               | `string`  | Nhãn hiển thị do quy trình cấu hình (vd `Ký duyệt`)          |
| `actionAt`                  | `string`  | Thời điểm thực hiện (ISO 8601)                               |
| `comment`                   | `string`  | Ý kiến người xử lý                                           |
| `actorName`                 | `string`  | Họ tên người thực hiện                                       |
| `actorUsername`             | `string`  | Username — **chỉ** với bước ký bằng tài khoản nội bộ         |
| `actorEmail` / `actorPhone` | `string`  | Email / SĐT người thực hiện                                  |

<Note>
  Bản ghi `OVERDUE` do hệ thống sinh khi bước quá hạn; `actor*` khi đó là người được giao bước, không phải người bấm nút.
</Note>

### Lỗi

| HTTP  | Nguyên nhân                                                    |
| ----- | -------------------------------------------------------------- |
| `404` | `documentId` không tồn tại, hoặc nằm ngoài phạm vi đọc của bạn |

***

## Phạm vi dữ liệu

* Danh sách công việc **luôn giới hạn theo người dùng đã xác thực**: công việc gán trực tiếp, gán cho vai trò họ đảm nhiệm, hoặc do người khác **uỷ quyền** cho họ (uỷ quyền chỉ áp cho phần chờ xử lý).
* Khi xác thực bằng `X-API-Key`, kết quả còn bị giới hạn trong **tổ chức của API Key**. Với access token thì không — phạm vi giống hệt những gì người dùng thấy trên web/app.
* Với lịch sử phê duyệt hồ sơ, người ký bên ngoài chỉ đọc được hồ sơ mà họ có tham gia.
* Không có công việc nào → `items` là mảng rỗng, `total` bằng `0`. Không trả `404`.

<Tip>
  `total` được tính theo đúng cách web/app đếm — phần chờ xử lý đếm số công việc, phần đã xử lý đếm số lượt xử lý — nên con số khớp với màn hình *Xử lý công việc* của người dùng.
</Tip>

***

## Lỗi chung

| HTTP  | Nguyên nhân                                                                                                                                                                                    |
| ----- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `400` | `status` không thuộc `{pending, approved, rejected, expired, completed, all}`; `page`/`pageSize` không phải số nguyên dương; `pageSize` lớn hơn `100`; `fromDate`/`toDate` không đúng ISO 8601 |
| `401` | API Key sai/thu hồi/hết hạn, API Key chưa gắn người dùng, tài khoản không hoạt động, hoặc access token sai/hết hạn                                                                             |

Chi tiết: [Mã lỗi](/api-reference/ma-loi).

***

## Bước tiếp theo

<CardGroup cols={2}>
  <Card title="API Hồ sơ" icon="file-signature" href="/api-reference/endpoint/ho-so">
    Tạo hồ sơ, tra cứu trạng thái đầy đủ và tải file
  </Card>

  <Card title="Webhook" icon="bell" href="/api-reference/webhook">
    Nhận thông báo thay vì hỏi vòng (polling)
  </Card>
</CardGroup>
