> ## 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.

# Payload tham chiếu

> Cấu trúc data của từng event webhook, block relatedParties và ví dụ JSON

Mọi event dùng chung envelope `{ id, type, createdAt, data }` — xem [Tổng quan](https://docs.econtractid.com/api-reference/webhook.md#headers). Trang này mô tả phần `data`.

Nguyên tắc chung:

* **Mã, không phải ID nội bộ.** `documentId` là mã hồ sơ bạn cấp, `transactionId` là mã tiến trình, `documentUuid` là UUID công khai.
* **Tương thích tiến.** Hệ thống có thể thêm trường mới vào `data`. Bộ parse của bạn phải bỏ qua trường chưa biết thay vì báo lỗi.
* `metadata` luôn là bản echo của `metadata` bạn gửi khi tạo hồ sơ (`{}` nếu không gửi).

***

## `relatedParties`

Có trong `data` của mọi event `notification.*` và `document.*`. Cho biết **ai tạo hồ sơ** và **những ai đã xử lý** tính đến thời điểm gửi event — đủ để bạn tự gửi thông báo cho người liên quan.

```json theme={null}
"relatedParties": {
  "creator": {
    "type": "internal",
    "name": "Trần Văn B",
    "email": "b@congty.vn",
    "phone": null,
    "userName": "tranvanb"
  },
  "actors": [
    {
      "order": 0,
      "stepCode": "TP_DUYET",
      "stepName": "Trưởng phòng duyệt",
      "action": "approved",
      "actionLabel": "Duyệt",
      "actedAt": "2026-10-07T07:00:00.000Z",
      "comment": null,
      "type": "internal",
      "name": "Lê Thị C",
      "email": "c@congty.vn",
      "phone": null,
      "userName": "lethic"
    }
  ]
}
```

**creator** `object | null`

Người tạo hồ sơ. Luôn là tài khoản của tổ chức (`type: "internal"`); với hồ sơ tạo qua API là tài khoản tích hợp.

**actors** `array`

Mỗi phần tử là **một lần xử lý** (duyệt/ký hoặc từ chối), sắp theo `actedAt` tăng dần. Một người xử lý nhiều bước sẽ xuất hiện nhiều lần. Mảng rỗng khi chưa ai xử lý (ví dụ event giao việc của bước đầu tiên).

**Trường của mỗi actor**

**order** `number | null`

Thứ tự bước, **bắt đầu từ 0**.

**stepCode / stepName** `string | null`

Mã và tên bước.

**action** `'approved' | 'rejected'`

Kết quả xử lý. Ký cũng là `approved`.

**actionLabel** `string | null`

Nhãn hành động hiển thị trên giao diện, ví dụ "Duyệt", "Từ chối".

**actedAt** `string | null`

Thời điểm xử lý (ISO 8601).

**comment** `string | null`

Ý kiến kèm theo, hoặc lý do từ chối.

**type** `'internal' | 'external'`

`external` = người ký được mời qua email/số điện thoại hoặc đối tác.

**name / email / phone / userName** `string | null`

Thông tin liên hệ. Người ký được mời bằng số điện thoại thường có `email: null`.

> [!NOTE]
>
> `relatedParties` không bao giờ chứa `credentials`. Bước quá hạn không tạo actor, vì không ai thực sự xử lý.

Gợi ý lấy danh sách người cần báo, bỏ trùng và chọn kênh gửi:

```js theme={null}
function peopleToNotify(data, { exclude } = {}) {
  const { creator, actors } = data.relatedParties;
  const seen = new Set();
  const result = [];
  for (const person of [creator, ...actors]) {
    if (!person) continue;
    const key = person.email ? person.email.toLowerCase() : person.phone;
    if (!key || seen.has(key) || key === exclude) continue;
    seen.add(key);
    result.push({ name: person.name, channel: person.email ? 'email' : 'sms', to: person.email ?? person.phone });
  }
  return result;
}
```

***

## Event `notification.*`

Năm event dùng chung một cấu trúc; `notification.task_completed` có thêm `actor` và `nextStep`.

### Trường chung

| Trường | Kiểu | Mô tả |
| - | - | - |
| `transactionId` | `string \| null` | Mã tiến trình |
| `documentId` | `string \| null` | Mã hồ sơ bạn cấp |
| `documentUuid` | `string \| null` | UUID hồ sơ |
| `documentTitle` | `string \| null` | Tên hồ sơ |
| `totalSteps` | `number` | Tổng số bước của quy trình |
| `step` | `object \| null` | Bước mà event nói tới; `null` với `process_finished` |
| `step.stepCode` / `step.stepName` | `string \| null` | Mã và tên bước |
| `step.order` | `number \| null` | Thứ tự bước, **bắt đầu từ 0** |
| `recipients[]` | `array` | Người nhận thông báo của event này — xem bảng dưới |
| `signUrl` | `string \| null` | Link mở công việc ký (event giao việc) hoặc link mở hồ sơ (các event còn lại) |
| `expireAt` | `string \| null` | Hạn xử lý bước; chỉ có ở event giao việc |
| `prevActorName` | `string \| null` | Tên người vừa xử lý — ý nghĩa theo từng event, xem bảng dưới |
| `completeDate` | `string \| null` | Thời điểm bước/quy trình kết thúc; `null` ở event giao việc |
| `note` | `string \| null` | Lý do từ chối (`task_rejected`) hoặc ý kiến khi duyệt (`task_completed`) |
| `relatedParties` | `object` | [Người tạo + những người đã xử lý](#relatedparties) |
| `metadata` | `object` | Echo `metadata` bạn gửi |

### Khác nhau giữa các event

| Event | `recipients[]` | `prevActorName` |
| - | - | - |
| `task_assigned_internal` | Nhân sự nội bộ được giao | Người xử lý bước trước; bước đầu là người tạo |
| `task_assigned_external` | Người ký bên ngoài (một người), có thể kèm `credentials` | Như trên |
| `task_completed` | Gợi ý người nên báo: người tạo + những người đã xử lý trước, đã bỏ trùng, trừ người vừa xử lý | Người vừa hoàn tất bước |
| `task_rejected` | Những người đã xử lý, gồm cả người từ chối | Người từ chối |
| `process_finished` | Những người đã xử lý | Người xử lý bước cuối |

* `step`: bước vừa giao (`task_assigned_*`), bước vừa xong (`task_completed`), bước bị từ chối (`task_rejected`); `null` ở `process_finished`.
* `signUrl`: link mở công việc ký ở `task_assigned_*`; link mở hồ sơ ở ba event còn lại.

> [!NOTE]
>
> `recipients[]` của `task_rejected` và `process_finished` **không gồm người tạo hồ sơ**. Lấy người tạo ở `relatedParties.creator`.

### `recipients[]`

| Trường | Kiểu | Mô tả |
| - | - | - |
| `type` | `'internal' \| 'external'` | Nhân sự nội bộ hay người ký bên ngoài |
| `name` / `email` / `phone` | `string \| null` | Thông tin người nhận |
| `credentials` | `object \| null` | Thông tin đăng nhập — **chỉ có ở `task_assigned_external`** |
| `credentials.userName` | `string` | Tên đăng nhập |
| `credentials.password` | `string \| null` | Mật khẩu **dạng văn bản thuần**, hoặc `null` nếu không cấp mật khẩu mới |

Ba biến thể của `credentials`: `null` (không có tài khoản) · `{ userName, password: null }` · `{ userName, password }`.

Bước mời người ký **bằng số điện thoại** có `email: null` và `phone` có giá trị. Luôn kiểm tra trường nào khác `null` rồi mới chọn kênh gửi.

> [!WARNING]
>
> `credentials.password` là mật khẩu thật. Không ghi payload của `task_assigned_external` vào log.

### Ví dụ

> [tab] task\_assigned\_external
>
> Một bước được giao cho người ký bên ngoài.
>
> ```json theme={null}
> {
>   "id": "evt_770e8400-e29b-41d4-a716-446655440001",
>   "type": "notification.task_assigned_external",
>   "createdAt": "2026-10-07T07:00:05.000Z",
>   "data": {
>     "transactionId": "PI000042",
>     "documentId": "HD-2026-001",
>     "documentUuid": "abc-uuid-folder",
>     "documentTitle": "Hợp đồng dịch vụ",
>     "totalSteps": 3,
>     "step": { "stepCode": "KH_KY", "stepName": "Khách hàng ký", "order": 1 },
>     "recipients": [
>       {
>         "type": "external",
>         "name": "Nguyễn Văn A",
>         "email": "a@khachhang.com",
>         "phone": null,
>         "credentials": { "userName": "079200001234", "password": "..." }
>       }
>     ],
>     "signUrl": "https://app.econtractid.com/tasks?id=12345",
>     "expireAt": "2026-10-10T07:00:05.000Z",
>     "prevActorName": "Lê Thị C",
>     "completeDate": null,
>     "note": null,
>     "relatedParties": {
>       "creator": { "type": "internal", "name": "Trần Văn B", "email": "b@congty.vn", "phone": null, "userName": "tranvanb" },
>       "actors": [
>         { "order": 0, "stepCode": "TP_DUYET", "stepName": "Trưởng phòng duyệt", "action": "approved", "actionLabel": "Duyệt", "actedAt": "2026-10-07T07:00:00.000Z", "comment": null, "type": "internal", "name": "Lê Thị C", "email": "c@congty.vn", "phone": null, "userName": "lethic" }
>       ]
>     },
>     "metadata": { "tenantCode": "T001" }
>   }
> }
> ```

> [tab] task\_assigned\_internal
>
> Một bước được giao cho nhân sự nội bộ. `credentials` luôn `null`.
>
> ```json theme={null}
> {
>   "id": "evt_770e8400-e29b-41d4-a716-446655440002",
>   "type": "notification.task_assigned_internal",
>   "createdAt": "2026-10-07T06:30:00.000Z",
>   "data": {
>     "transactionId": "PI000042",
>     "documentId": "HD-2026-001",
>     "documentUuid": "abc-uuid-folder",
>     "documentTitle": "Hợp đồng dịch vụ",
>     "totalSteps": 3,
>     "step": { "stepCode": "TP_DUYET", "stepName": "Trưởng phòng duyệt", "order": 0 },
>     "recipients": [
>       { "type": "internal", "name": "Lê Thị C", "email": "c@congty.vn", "phone": null, "credentials": null }
>     ],
>     "signUrl": "https://app.econtractid.com/tasks?id=12344",
>     "expireAt": null,
>     "prevActorName": "Trần Văn B",
>     "completeDate": null,
>     "note": null,
>     "relatedParties": {
>       "creator": { "type": "internal", "name": "Trần Văn B", "email": "b@congty.vn", "phone": null, "userName": "tranvanb" },
>       "actors": []
>     },
>     "metadata": { "tenantCode": "T001" }
>   }
> }
> ```

> [tab] task\_completed
>
> Một bước được duyệt/ký xong. Có thêm `actor` (người hoàn tất bước) và `nextStep` (bước đang chờ; `null` nếu đây là bước cuối).
>
> ```json theme={null}
> {
>   "id": "evt_770e8400-e29b-41d4-a716-446655440003",
>   "type": "notification.task_completed",
>   "createdAt": "2026-10-07T07:00:01.000Z",
>   "data": {
>     "transactionId": "PI000042",
>     "documentId": "HD-2026-001",
>     "documentUuid": "abc-uuid-folder",
>     "documentTitle": "Hợp đồng dịch vụ",
>     "totalSteps": 3,
>     "step": { "stepCode": "TP_DUYET", "stepName": "Trưởng phòng duyệt", "order": 0 },
>     "recipients": [
>       { "type": "internal", "name": "Trần Văn B", "email": "b@congty.vn", "phone": null, "credentials": null }
>     ],
>     "signUrl": "https://app.econtractid.com/folders?id=9001",
>     "expireAt": null,
>     "prevActorName": "Lê Thị C",
>     "completeDate": "2026-10-07T07:00:00.000Z",
>     "note": null,
>     "actor": {
>       "order": 0, "stepCode": "TP_DUYET", "stepName": "Trưởng phòng duyệt",
>       "action": "approved", "actionLabel": "Duyệt", "actedAt": "2026-10-07T07:00:00.000Z", "comment": null,
>       "type": "internal", "name": "Lê Thị C", "email": "c@congty.vn", "phone": null, "userName": "lethic"
>     },
>     "nextStep": { "stepCode": "KH_KY", "stepName": "Khách hàng ký", "order": 1 },
>     "relatedParties": {
>       "creator": { "type": "internal", "name": "Trần Văn B", "email": "b@congty.vn", "phone": null, "userName": "tranvanb" },
>       "actors": [
>         { "order": 0, "stepCode": "TP_DUYET", "stepName": "Trưởng phòng duyệt", "action": "approved", "actionLabel": "Duyệt", "actedAt": "2026-10-07T07:00:00.000Z", "comment": null, "type": "internal", "name": "Lê Thị C", "email": "c@congty.vn", "phone": null, "userName": "lethic" }
>       ]
>     },
>     "metadata": { "tenantCode": "T001" }
>   }
> }
> ```
>
> | Trường riêng | Kiểu | Mô tả |
> | - | - | - |
> | `actor` | `object` | Người hoàn tất bước, cùng cấu trúc với một phần tử của `relatedParties.actors`. Với bước nhiều người cùng ký là người ký sau cùng |
> | `nextStep` | `object \| null` | `{ stepCode, stepName, order }` của bước đang chờ; `null` khi quy trình đã xong |

> [tab] task\_rejected
>
> Một bước bị từ chối. `note` là lý do, `prevActorName` là người từ chối.
>
> ```json theme={null}
> {
>   "id": "evt_770e8400-e29b-41d4-a716-446655440004",
>   "type": "notification.task_rejected",
>   "createdAt": "2026-10-07T08:30:00.000Z",
>   "data": {
>     "transactionId": "PI000042",
>     "documentId": "HD-2026-001",
>     "documentUuid": "abc-uuid-folder",
>     "documentTitle": "Hợp đồng dịch vụ",
>     "totalSteps": 3,
>     "step": { "stepCode": "KH_KY", "stepName": "Khách hàng ký", "order": 1 },
>     "recipients": [
>       { "type": "external", "name": "Nguyễn Văn A", "email": "a@khachhang.com", "phone": null, "credentials": null },
>       { "type": "internal", "name": "Lê Thị C", "email": "c@congty.vn", "phone": null, "credentials": null }
>     ],
>     "signUrl": "https://app.econtractid.com/folders?id=9001",
>     "expireAt": null,
>     "prevActorName": "Nguyễn Văn A",
>     "completeDate": "2026-10-07T08:29:00.000Z",
>     "note": "Sai thông tin trên hợp đồng",
>     "relatedParties": {
>       "creator": { "type": "internal", "name": "Trần Văn B", "email": "b@congty.vn", "phone": null, "userName": "tranvanb" },
>       "actors": [
>         { "order": 0, "stepCode": "TP_DUYET", "stepName": "Trưởng phòng duyệt", "action": "approved", "actionLabel": "Duyệt", "actedAt": "2026-10-07T07:00:00.000Z", "comment": null, "type": "internal", "name": "Lê Thị C", "email": "c@congty.vn", "phone": null, "userName": "lethic" },
>         { "order": 1, "stepCode": "KH_KY", "stepName": "Khách hàng ký", "action": "rejected", "actionLabel": "Từ chối", "actedAt": "2026-10-07T08:29:00.000Z", "comment": "Sai thông tin trên hợp đồng", "type": "external", "name": "Nguyễn Văn A", "email": "a@khachhang.com", "phone": null, "userName": "079200001234" }
>       ]
>     },
>     "metadata": { "tenantCode": "T001" }
>   }
> }
> ```

> [tab] process\_finished
>
> Toàn bộ quy trình hoàn tất. `step` là `null`.
>
> ```json theme={null}
> {
>   "id": "evt_770e8400-e29b-41d4-a716-446655440005",
>   "type": "notification.process_finished",
>   "createdAt": "2026-10-07T09:45:00.000Z",
>   "data": {
>     "transactionId": "PI000042",
>     "documentId": "HD-2026-001",
>     "documentUuid": "abc-uuid-folder",
>     "documentTitle": "Hợp đồng dịch vụ",
>     "totalSteps": 3,
>     "step": null,
>     "recipients": [
>       { "type": "internal", "name": "Phạm Văn D", "email": "d@congty.vn", "phone": null, "credentials": null },
>       { "type": "external", "name": "Nguyễn Văn A", "email": "a@khachhang.com", "phone": null, "credentials": null },
>       { "type": "internal", "name": "Lê Thị C", "email": "c@congty.vn", "phone": null, "credentials": null }
>     ],
>     "signUrl": "https://app.econtractid.com/folders?id=9001",
>     "expireAt": null,
>     "prevActorName": "Phạm Văn D",
>     "completeDate": "2026-10-07T09:44:00.000Z",
>     "note": null,
>     "relatedParties": {
>       "creator": { "type": "internal", "name": "Trần Văn B", "email": "b@congty.vn", "phone": null, "userName": "tranvanb" },
>       "actors": [
>         { "order": 0, "stepCode": "TP_DUYET", "stepName": "Trưởng phòng duyệt", "action": "approved", "actionLabel": "Duyệt", "actedAt": "2026-10-07T07:00:00.000Z", "comment": null, "type": "internal", "name": "Lê Thị C", "email": "c@congty.vn", "phone": null, "userName": "lethic" },
>         { "order": 1, "stepCode": "KH_KY", "stepName": "Khách hàng ký", "action": "approved", "actionLabel": "Ký", "actedAt": "2026-10-07T08:29:00.000Z", "comment": null, "type": "external", "name": "Nguyễn Văn A", "email": "a@khachhang.com", "phone": null, "userName": "079200001234" },
>         { "order": 2, "stepCode": "GD_KY", "stepName": "Giám đốc ký", "action": "approved", "actionLabel": "Ký", "actedAt": "2026-10-07T09:44:00.000Z", "comment": null, "type": "internal", "name": "Phạm Văn D", "email": "d@congty.vn", "phone": null, "userName": "phamvand" }
>       ]
>     },
>     "metadata": { "tenantCode": "T001" }
>   }
> }
> ```

***

## Event `document.*`

### `document.completed`

```json theme={null}
{
  "id": "evt_550e8400-e29b-41d4-a716-446655440000",
  "type": "document.completed",
  "createdAt": "2026-05-16T17:58:12.345Z",
  "data": {
    "documentId": "HD-2026-001",
    "documentUuid": "abc-uuid-folder",
    "documentTitle": "Hợp đồng dịch vụ — Nguyễn Văn A",
    "transactionId": "PI000042",
    "status": "COMPLETED",
    "completedAt": "2026-05-16T17:58:10.000Z",
    "files": [
      {
        "type": "signed_document",
        "url": "https://minio.../abc_signed.pdf?X-Amz-Signature=...",
        "expiresAt": "2026-05-23T17:58:10.000Z",
        "name": "Hop_dong_lao_dong_signed.pdf",
        "mimeType": "application/pdf",
        "sizeBytes": 245678,
        "ecmNodeUuid": "550e8400-e29b-41d4-a716-446655440001",
        "ecmClassCode": "CONTRACT_LABOR"
      }
    ],
    "signedCount": 2,
    "totalSigners": 2,
    "signers": [
      { "stepName": "Người lao động ký", "stepCode": "STEP_SIGN_HR", "email": "a@x.com", "identityNumber": "079...", "status": "SIGNED", "signedAt": "2026-05-16T17:55:00.000Z" },
      { "stepName": "Đại diện đối tác ký", "stepCode": "STEP_SIGN_PARTNER", "email": "b@x.com", "taxCode": "0312345678", "status": "SIGNED", "signedAt": "2026-05-16T17:57:00.000Z" }
    ],
    "relatedParties": { "creator": { "type": "internal", "name": "Trần Văn B", "email": "b@congty.vn", "phone": null, "userName": "tranvanb" }, "actors": [] },
    "metadata": { "tenantCode": "T001", "contractValue": 100000 }
  }
}
```

Ví dụ rút gọn `relatedParties.actors` — thực tế chứa mọi lần xử lý, cấu trúc như [mục trên](#relatedparties).

`files[]` được thiết kế **tương thích tiến**: bạn có thể bỏ qua các `type` chưa nhận diện, cho phép hệ thống thêm loại file mới mà không phá vỡ tích hợp cũ. `ecmNodeUuid` chính là `fileUuid` dùng cho [endpoint tải file](https://docs.econtractid.com/api-reference/endpoint/ho-so.md).

> [!WARNING]
>
> `signers[]` và `totalSigners` **chỉ tính người ký bên ngoài** — bước của nhân sự nội bộ và bước theo vai trò bị loại khỏi payload. Vì vậy `totalSigners` có thể nhỏ hơn `requiredCount` của [endpoint tra cứu](https://docs.econtractid.com/api-reference/endpoint/ho-so.md); đừng đối soát trực tiếp hai con số này. Cần cả người xử lý nội bộ thì dùng `relatedParties.actors`.

> [!WARNING]
>
> `files[].url` là presigned URL — lấy thẳng từ JSON parser rồi GET, đừng đọc từ log thô hay re-marshal (Go mặc định escape `&`; nếu buộc phải, dùng `encoder.SetEscapeHTML(false)`). Dấu hiệu sai: URL có `%5Cu0026`, kho lưu trữ trả `AccessDenied` dù chưa hết hạn.

### `document.rejected`

```json theme={null}
{
  "id": "evt_660e8400-e29b-41d4-a716-446655440000",
  "type": "document.rejected",
  "createdAt": "2026-05-16T18:10:00.000Z",
  "data": {
    "documentId": "HD-2026-002",
    "documentUuid": "def-uuid-folder",
    "documentTitle": "Hợp đồng dịch vụ — Trần Văn B",
    "transactionId": "PI000043",
    "status": "REJECTED",
    "rejectedAt": "2026-05-16T18:09:58.000Z",
    "rejectedBy": {
      "fullName": "Trần Văn B",
      "email": "b@x.com",
      "phone": "+84909876543",
      "identityNumber": "079209876543"
    },
    "reason": "Sai thông tin trên hợp đồng",
    "files": [
      {
        "type": "input_document",
        "url": "https://minio.../template.pdf?X-Amz-Signature=...",
        "expiresAt": "2026-05-23T18:10:00.000Z",
        "name": "contract_template.pdf",
        "mimeType": "application/pdf",
        "sizeBytes": 198234,
        "ecmNodeUuid": "660e8400-e29b-0001-a716-446655440000",
        "ecmClassCode": "CONTRACT_LABOR"
      }
    ],
    "totalSigners": 2,
    "signers": [
      { "stepName": "Người lao động ký", "stepCode": "STEP_SIGN_HR", "email": "a@x.com", "status": "SIGNED", "signedAt": "2026-05-16T18:05:00.000Z" },
      { "stepName": "Đại diện đối tác ký", "stepCode": "STEP_SIGN_PARTNER", "email": "b@x.com", "status": "REJECTED" }
    ],
    "relatedParties": { "creator": { "type": "internal", "name": "Lê Thị C", "email": "c@congty.vn", "phone": null, "userName": "lethic" }, "actors": [] },
    "metadata": { "tenantCode": "T001" }
  }
}
```

Khác `document.completed` ở chỗ: không có bản ký hoàn chỉnh trong `files[]` (chỉ file đầu vào và đính kèm), không có `signedCount`, và có thêm:

| Trường | Mô tả |
| - | - |
| `rejectedAt` | Thời điểm người ký bấm từ chối |
| `rejectedBy` | Người từ chối: `fullName`, `email`, `phone`, `identityNumber` (trường nào không có thì vắng mặt) |
| `reason` | Lý do người từ chối nhập; `"rejected"` nếu để trống |

***

## Event `webhook.test`

Payload và cách kiểm thử: xem [Tổng quan — `webhook.test`](https://docs.econtractid.com/api-reference/webhook).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.