---
title: "Chính sách"
description: "Tìm hiểu cách các chính sách lập trình được của Fystack đánh giá giao dịch rút tiền, chuyển tiền Web3, lệnh gọi hợp đồng và ký message, cũng như cách tạo, xác thực, phê duyệt và quản lý các quy tắc chính sách."
url: https://docs.fystack.io/vi/policies
last_updated: 2026-11-13
---

> ## Documentation index
> Fetch the complete documentation index at: https://docs.fystack.io/llms.txt
> Use it to discover all available pages before exploring further.

# Chính sách

Chính sách của Fystack là các rào chắn có thể lập trình cho những thao tác nhạy cảm trên ví. Một chính sách áp dụng cho một workspace, có thể thu hẹp xuống các ví cụ thể, và chứa các quy tắc đánh giá một biểu thức dựa trên payload hành động có cấu trúc.

Các quy tắc được thực thi cho bốn hành động:

- `withdrawal.create` (trigger_action): Được đánh giá trước khi giao dịch rút tiền được tạo. `DENY` sẽ chặn yêu cầu.
  `ALLOW` khớp sẽ bỏ qua phê duyệt giao dịch và cho phép giao dịch rút tiền
  chuyển sang bước ký.
- `web3.transfer` (trigger_action): Được đánh giá khi một giao dịch chuyển coin gốc hoặc ERC-20 được gửi qua
  Web3 raw-transaction API. Sử dụng cùng các trường `withdrawal.*` như
  `withdrawal.create`, nên một điều kiện được hiểu giống nhau trên cả hai trigger.
  Các trường velocity không khả dụng, vì những giao dịch chuyển này không phải
  là rút tiền. Giao dịch chuyển ERC-20 cũng được đánh giá như `web3.contract_call`.
- `web3.contract_call` (trigger_action): Được đánh giá trước khi các lệnh gọi hợp đồng EVM và giao dịch chuyển token
  ERC-20 được gửi đi ký. `DENY` ghi nhận hoạt động là `denied_by_policy`.
  `ALLOW` khớp sẽ bỏ qua phê duyệt giao dịch và chuyển sang bước ký.
- `web3.sign_message` (trigger_action): Được đánh giá khi một ví được yêu cầu ký message bằng `personal_sign`,
  `eth_sign` hoặc `eth_signTypedData_v4`. Chỉ hỗ trợ từ chối: một message được
  ký luôn phải qua phê duyệt.

> **Info.** Schema chính sách được sinh ra từ action schema ở backend trong Apex. Hãy dùng
> [Lấy schema chính sách](#get-the-policy-schema) khi xây dựng UI builder hoặc
> kiểm tra động tính khả dụng của các trường. Để có các quy tắc dựng sẵn, xem
> [Mẫu chính sách](https://docs.fystack.io/product/policies.md#policy-templates).

---

## Cấu trúc chính sách

Chính sách là vùng chứa. Quy tắc là đơn vị thực thi.

```json
{
  "name": "Large withdrawal guard",
  "approval_group_id": "a1b2c3d4-e5f6-7890-1234-567890abcdef",
  "wallet_ids": [],
  "rules": [
    {
      "trigger_action": "withdrawal.create",
      "condition": "withdrawal.value_usd > 10000 && !withdrawal.is_whitelisted",
      "effect": "DENY"
    }
  ]
}
```

- `approval_group_id` (string): Nhóm phê duyệt xem xét việc tạo, chỉnh sửa, xóa chính sách và các thay đổi
  quy tắc.
- `wallet_ids` (string\[]): Các ví mà chính sách này áp dụng. Mảng rỗng nghĩa là mọi ví trong
  workspace.
- `rules` (array): Tối đa 50 quy tắc. Mỗi quy tắc có `trigger_action`, `condition`, `effect`,
  `description` tùy chọn và `is_enabled` tùy chọn.

### Trạng thái chính sách

- `pending` (status): Đã tạo nhưng chưa được phê duyệt. Chính sách đang chờ sẽ không được đánh giá.
- `active` (status): Đã được phê duyệt và đang hoạt động. Bộ đánh giá chỉ tải các chính sách đang hoạt động.
- `inactive` (status): Đã bị vô hiệu hóa và không được đánh giá.
- `rejected` (status): Bị từ chối trong quá trình phê duyệt và không được đánh giá.

---

## Đánh giá chính sách

Với mỗi yêu cầu được bảo vệ, Fystack tải các chính sách đang hoạt động của workspace, biên dịch các quy tắc được bật, lọc các quy tắc khớp theo hành động và ví mục tiêu, sau đó xác định kết quả:

1. Nếu bất kỳ quy tắc khớp nào có `effect: "DENY"`, hành động sẽ bị chặn.
2. Ngược lại, nếu bất kỳ quy tắc khớp nào có `effect: "ALLOW"`, hành động được tiếp tục và bỏ qua phê duyệt giao dịch.
3. Ngược lại, không có quy tắc chính sách nào khớp. Hành động tiếp tục theo luồng phê duyệt thông thường.

`DENY` luôn được ưu tiên hơn `ALLOW`, nên thứ tự quy tắc không bao giờ thay đổi kết quả. Trong nhóm effect thắng, quy tắc khớp đầu tiên theo thứ tự khai báo được dùng để quy kết, nhờ đó API có thể trả về `rule_id` và lý do chính sách ổn định.

Không có effect "yêu cầu phê duyệt" riêng. Phê duyệt là mặc định cho mọi hành động không khớp với quy tắc `ALLOW` nào.

> **Warning.** Việc đánh giá theo cơ chế fail-closed. Lỗi cache, cơ sở dữ liệu, biên dịch
> hoặc đánh giá runtime đều dẫn đến từ chối hành động. Mỗi lần đánh giá có thời
> gian chờ 100 ms.

### Phạm vi và cache

Chính sách được giới hạn theo workspace. Apex cache một gói chính sách đã biên dịch cho mỗi workspace và vô hiệu hóa nó sau khi có phê duyệt, từ chối chính sách hoặc thay đổi ví mục tiêu. Việc lọc ví diễn ra trong quá trình đánh giá, nên một gói của workspace có thể phục vụ tất cả các ví trong workspace đó.

---

## Điều kiện

`condition` là một biểu thức phải trả về giá trị boolean. Tham chiếu các trường theo tên phần và tên trường, ví dụ `principal.role`, `withdrawal.value_usd`, `wallet.purpose` hoặc `resource.method_selector`.

Sử dụng các toán tử boolean, so sánh và kiểm tra thành viên thông thường:

```txt
&&  ||  !  ==  !=  >  >=  <  <=  in
```

`in` kiểm tra thành viên trong một danh sách literal hoặc một trường kiểu danh sách, ví dụ `principal.api_key_id in ["<api_key_id>"]` hoặc `"0x…" in resource.permit_tokens`.

Ví dụ:

- `Chặn rút tiền lớn đến địa chỉ ngoài danh sách cho phép` (DENY): `withdrawal.value_usd > 10000 && !withdrawal.is_whitelisted`
- `Giới hạn mỗi ví ở mức $100,000 mỗi ngày` (DENY): `wallet.projected_outflow_24h > 100000`
- `Giữ tiền lưu ký bên trong workspace` (DENY): `wallet.purpose == "custody" && !withdrawal.destination_is_internal`
- `Bỏ qua phê duyệt cho API key chi trả` (ALLOW): `principal.initiator_type == "api_key" && principal.api_key_id in     ["<api_key_id>"] && withdrawal.value_usd < 1000`
- `Bỏ qua phê duyệt cho các mục sổ địa chỉ đã lâu` (ALLOW): `withdrawal.is_whitelisted && withdrawal.address_age_sec >= 86400 &&
      withdrawal.value_usd <= 1000`
- `Chặn rút tiền giá trị cao vào cuối tuần` (DENY): `(context.day_of_week == "Saturday" || context.day_of_week == "Sunday") &&
      withdrawal.value_usd > 25000`
- `Chặn giao dịch chuyển ERC-20 có gas cao` (DENY): `resource.method_selector == "0xa9059cbb" && resource.gas_limit > 100000`
- `Chặn token permit không giới hạn` (DENY): `resource.is_permit && resource.permit_amount_is_unlimited`

> **Warning.** `resource.decoded_args` là động. Hãy bảo vệ các trường động bằng `has(...)`
> trước khi đọc chúng, ví dụ `has(resource.decoded_args.to) &&
>   resource.decoded_args.to == "0x000000000000000000000000000000000000dead"`.

### Trường tham chiếu

Các trường được đánh dấu `ref` trong schema chứa ID hoặc mã của một thực thể khác trong workspace: `workspace_user`, `api_key`, `wallet`, `address_book`, `network` hoặc `asset_symbol`. Các condition builder nên hiển thị bộ chọn cho những trường này.

Khi một quy tắc được lưu, Fystack kiểm tra rằng mỗi ID được tham chiếu thuộc về workspace của bạn. Nếu một thực thể sau đó bị xóa hoặc thu hồi, quy tắc vẫn giữ ID đó và chỉ có thể khớp ít hơn, không bao giờ nhiều hơn.

---

## Action schema

Action schema định nghĩa các trường có thể dùng trong một điều kiện. Các trường được đánh dấu `deprecated` vẫn được đánh giá cho các quy tắc hiện có nhưng không nên dùng trong quy tắc mới.

### Các trường chung

Mọi trigger action đều cung cấp các trường sau.

- `principal.user_id` (string · ref workspace_user): ID của thành viên workspace đã khởi tạo hành động. Để trống khi bên
  khởi tạo là API key.
- `principal.role` (string): Vai trò trong workspace. Một trong `owner`, `admin`, `signer`, `proposer` hoặc `viewer`.
- `principal.initiator_type` (string): `user` cho phiên web, hoặc `api_key` cho API key.
- `principal.api_key_id` (string · ref api_key): ID của API key đã khởi tạo hành động. Để trống với phiên web, vì vậy hãy
  kết hợp với `principal.initiator_type`.
- `principal.user_email` (string · deprecated): Email của người dùng khởi tạo. Hãy dùng `principal.user_id` thay thế, vì
  email có thể thay đổi.
- `wallet.id` (string · ref wallet): ID của ví nguồn. Dùng cho các quy tắc nhắm đến các ví cụ thể trong một
  chính sách.
- `wallet.purpose` (string): Mục đích của ví nguồn. Một trong `general`, `custody`, `payment`, `user`,
  `one_time_use`, `gas_tank` hoặc `deployment`.
- `wallet.type` (string): Loại ví nguồn. `standard` hoặc `mpc`.
- `context.hour` (integer): Giờ UTC tại thời điểm đánh giá, từ `0` đến `23`.
- `context.day_of_week` (string): Tên ngày trong tuần theo UTC, ví dụ `Monday` hoặc `Saturday`.

### Các trường rút tiền

Khả dụng trên `withdrawal.create` và `web3.transfer`.

- `withdrawal.amount` (number): Số lượng tài sản được yêu cầu.
- `withdrawal.value_usd` (number): Giá trị được yêu cầu tính bằng USD.
- `withdrawal.asset_symbol` (string · ref asset_symbol): Ký hiệu tài sản, chẳng hạn `USDT`, `ETH` hoặc `BTC`.
- `withdrawal.asset_is_native` (boolean): Tài sản có phải là tài sản gốc của mạng lưới hay không.
- `withdrawal.asset_is_known` (boolean): Token có nằm trong danh mục tài sản của Fystack hay không. Khi là `false`,
  `amount`, `value_usd` và `asset_symbol` sẽ trống, vì vậy hãy từ chối rõ ràng
  các token không xác định nếu cần.
- `withdrawal.token_address` (string): Địa chỉ hợp đồng token. Để trống với coin gốc.
- `withdrawal.destination_address` (string): Địa chỉ người nhận.
- `withdrawal.network_code` (string · ref network): Mã mạng lưới nội bộ.
- `withdrawal.is_whitelisted` (boolean): Địa chỉ đích có nằm trong bất kỳ mục sổ địa chỉ nào của workspace hay không.
- `withdrawal.address_book_id` (string · ref address_book): Mục sổ địa chỉ chứa địa chỉ đích. Một mục bao gồm tất cả các địa chỉ của
  nó, nên một mục hoạt động như một danh sách có tên.
- `withdrawal.address_age_sec` (number): Số giây kể từ khi địa chỉ đích được thêm vào mục sổ địa chỉ của nó.
  Dùng trường này cho các quy tắc thời gian chờ đối với người nhận mới thêm.
- `withdrawal.destination_is_internal` (boolean): Đích có phải là một ví khác trong cùng workspace hay không.
- `withdrawal.destination_wallet_id` (string · ref wallet): Ví đích khi đích là nội bộ.

### Các trường velocity của rút tiền

Chỉ khả dụng trên `withdrawal.create`. Mọi giá trị đều tính bằng USD trừ khi có ghi chú khác.

- `wallet.outflow_1h / outflow_6h / outflow_24h` (number): Dòng tiền ra thực tế của ví nguồn trong 1, 6 hoặc 24 giờ qua.
- `wallet.withdrawal_count_1h` (integer): Số lần thử rút tiền từ ví nguồn trong giờ qua.
- `wallet.pending_outflow` (number): Giá trị các giao dịch rút tiền từ ví nguồn chưa được thực thi.
- `wallet.projected_outflow_24h` (number): Dòng tiền ra thực tế trong 24 giờ, cộng dòng tiền ra đang chờ, cộng giao dịch
  rút tiền đang được kiểm tra, đối với ví nguồn.
- `wallet.asset_projected_outflow_24h` (number): Cùng phép dự báo đó cho ví nguồn nhưng tính theo đơn vị của tài sản được rút,
  ví dụ tối đa 5 BTC mỗi ngày.
- `workspace.outflow_1h / outflow_6h / outflow_24h` (number): Dòng tiền ra thực tế của workspace trong 1, 6 hoặc 24 giờ qua.
- `workspace.withdrawal_count_1h` (integer): Số lần thử rút tiền của workspace trong giờ qua.
- `workspace.pending_outflow` (number): Giá trị các giao dịch rút tiền của workspace chưa được thực thi.
- `workspace.projected_outflow_24h` (number): Dự báo của workspace: dòng tiền ra thực tế trong 24 giờ, cộng dòng tiền ra
  đang chờ, cộng giao dịch rút tiền đang được kiểm tra.
- `workspace.network_outflow_1h / network_outflow_6h / network_outflow_24h` (number): Dòng tiền ra thực tế của workspace trên mạng lưới hiện tại trong 1, 6 hoặc
  24 giờ qua.
- `workspace.network_withdrawal_count_1h` (integer): Số lần thử rút tiền của workspace trên mạng lưới hiện tại trong giờ qua.
- `workspace.network_pending_outflow` (number): Dòng tiền ra đang chờ của workspace trên mạng lưới hiện tại.
- `workspace.network_projected_outflow_24h` (number): Dự báo của workspace trên mạng lưới hiện tại.
- `workspace.initiator_projected_outflow_24h` (number): Dự báo cho các giao dịch rút tiền được tạo bởi cùng một thành viên hoặc API
  key, trên toàn workspace.

Các trường dòng tiền ra và số lượng là giá trị thực tế: chúng chỉ tính một giao dịch rút tiền sau khi nó đạt trạng thái cuối là đã thực thi hoặc thành công. Dòng tiền ra đang chờ tính các giao dịch rút tiền đang chờ phê duyệt, đang trong hàng đợi hoặc đang nạp gas, bất kể đã tồn tại bao lâu.

> **Info.** Khi một quy tắc đang hoạt động sử dụng trường pending hoặc projected, Fystack
> đánh giá lần lượt từng giao dịch rút tiền của workspace, nên hai yêu cầu đồng
> thời không thể cùng vượt qua một giới hạn. Yêu cầu phải chờ lượt quá 5 giây sẽ
> bị từ chối với HTTP `429` và có thể thử lại.

### Các trường web3.contract_call

- `resource.network_code` (string · ref network): Mã mạng lưới nội bộ.
- `resource.contract_address` (string): Địa chỉ hợp đồng viết thường lấy từ trường `to` của giao dịch thô.
- `resource.method_selector` (string): Selector 4 byte viết thường, ví dụ `0xa9059cbb`.
- `resource.method_name` (string): Tên phương thức lấy từ metadata của yêu cầu nếu được cung cấp.
- `resource.value_wei` (string): Giá trị coin gốc được gửi kèm lệnh gọi, biểu diễn dưới dạng chuỗi.
- `resource.gas_limit` (integer): Giới hạn gas lấy từ giao dịch thô.
- `resource.decoded_args` (map): Các đối số đã giải mã khi Fystack nhận diện được lệnh gọi. `transfer` của
  ERC-20 cung cấp `to` và `value`.

### Các trường web3.sign_message

- `resource.method` (string): Phương thức ký. Một trong `personal_sign`, `eth_sign` hoặc
  `eth_signTypedData_v4`.
- `resource.network_code` (string · ref network): Mã mạng lưới nội bộ.
- `resource.typed_data_primary_type` (string): Primary type EIP-712, dành cho message typed-data.
- `resource.typed_data_domain_name` (string): Domain name EIP-712, dành cho message typed-data.
- `resource.typed_data_verifying_contract` (string): Verifying contract EIP-712, dành cho message typed-data.
- `resource.is_permit` (boolean): `true` với các message EIP-2612, DAI và Permit2, cho phép bên chi tiêu di
  chuyển token sau này mà không cần chữ ký khác.
- `resource.permit_spender` (string): Địa chỉ được permit ủy quyền.
- `resource.permit_tokens` (string\[]): Các hợp đồng token mà permit bao gồm. Dùng với `in`, ví dụ
  `"0x…" in resource.permit_tokens`.
- `resource.permit_amount_is_unlimited` (boolean): `true` với các allowance giá trị tối đa (2^159 trở lên, hoặc DAI
  permit có đặt `allowed`).
- `resource.permit_deadline` (integer): Thời điểm Unix mà permit hoặc chữ ký của nó hết hạn. `0` khi message không
  có thời hạn.

---

## Vòng đời phê duyệt

Các thao tác tạo, cập nhật và xóa chính sách đều cần phê duyệt. Thao tác thay đổi sẽ tạo một yêu cầu phê duyệt `policy` và trả về `status: "pending_approval"` kèm `approval_request_id`. Thay đổi chính sách chỉ được áp dụng sau khi nhóm phê duyệt đạt ngưỡng.

Các thao tác tạo, cập nhật và xóa quy tắc tuân theo cùng mô hình khi chính sách cha có nhóm phê duyệt. Bản sửa đổi đang chờ lưu các khác biệt ở cấp trường để kiểm toán và xem xét.

Cập nhật ví mục tiêu qua `/wallets` được áp dụng ngay sau khi xác thực và vô hiệu hóa cache. Hãy dùng endpoint cập nhật chính sách khi bạn muốn các thay đổi ví mục tiêu được xem xét như một phần của bản sửa đổi chính sách lớn hơn.

---

## Xác thực

Các endpoint của Policy API chấp nhận yêu cầu được ký bằng API key hoặc bearer access token.

- `ACCESS-API-KEY` (header): UUID của API key cho các yêu cầu xác thực bằng HMAC.
- `ACCESS-TIMESTAMP` (header): Dấu thời gian UNIX tính bằng giây dùng để tạo chữ ký HMAC.
- `ACCESS-SIGN` (header): Chữ ký HMAC mã hóa Base64. Xem [Xác thực](https://docs.fystack.io/authentication.md) để biết định dạng ký.
- `Authorization` (header): Bearer access token cho các yêu cầu theo phiên người dùng.

> **Warning.** Các endpoint quyết định phê duyệt chính sách vẫn là endpoint theo phiên người dùng. Hãy dùng bearer access token cho các thao tác phê duyệt và từ chối yêu cầu phê duyệt.

## Cấu trúc phản hồi

Các phản hồi JSON thành công sử dụng cấu trúc envelope tiêu chuẩn của Fystack.

- `success` (boolean): `true` khi yêu cầu thành công.
- `message` (string): Thông báo phản hồi, thường là `success`.
- `code` (integer): Mã kết quả dạng số. Phản hồi thành công dùng `0`.
- `data` (object | array | null): Payload phản hồi riêng của từng endpoint.

Lỗi xác thực dùng cùng envelope với `success: false` và một mảng `errors`.

## Kiểu dữ liệu

### Policy

- `id` (string): UUID của chính sách.
- `created_at` (string): Dấu thời gian ISO khi chính sách được tạo.
- `updated_at` (string): Dấu thời gian ISO khi chính sách được cập nhật lần cuối.
- `name` (string): Tên chính sách. Từ 3 đến 100 ký tự.
- `description` (string): Mô tả tùy chọn. Tối đa 500 ký tự.
- `status` (string): Một trong `pending`, `rejected`, `active` hoặc `inactive`.
- `version` (integer): Số phiên bản của chính sách.
- `workspace_id` (string): UUID của workspace.
- `approval_group_id` (string | null): UUID của nhóm phê duyệt được gán cho chính sách.
- `wallet_ids` (string\[]): UUID của các ví mục tiêu. Mảng rỗng nghĩa là chính sách áp dụng cho tất cả các ví trong workspace.
- `rules` (PolicyRule\[]): Có mặt ở các endpoint tải sẵn quy tắc.
- `approval_group` (object): Có mặt ở các endpoint tải sẵn nhóm phê duyệt.
- `pending_approval_request` (object): Có mặt khi chính sách có yêu cầu phê duyệt đang chờ.

### PolicyRule

- `id` (string): UUID của quy tắc.
- `policy_id` (string): UUID của chính sách cha.
- `trigger_action` (string): Một trong `withdrawal.create`, `web3.transfer`, `web3.contract_call` hoặc `web3.sign_message`.
- `condition` (string): Biểu thức điều kiện boolean. Từ 1 đến 4000 ký tự.
- `effect` (string): Một trong `ALLOW` hoặc `DENY`.
- `description` (string): Mô tả tùy chọn. Tối đa 500 ký tự.
- `is_enabled` (boolean): Quy tắc có được bật hay không. Mặc định là `true` khi tạo nếu bỏ qua.

### Phản hồi thay đổi

Các endpoint thay đổi chính sách và quy tắc trả về payload thay đổi trong `data`.

- `status` (string): Một trong `applied`, `pending_approval` hoặc `deleted`, tùy theo thao tác.
- `policy` (Policy): Được trả về bởi các endpoint thay đổi chính sách khi phù hợp.
- `rule` (PolicyRule): Được trả về bởi các endpoint thay đổi quy tắc khi phù hợp.
- `approval_request_id` (string): Được trả về khi thay đổi đang chờ phê duyệt.

## Lấy schema chính sách

**Endpoint:** `GET /policy/schema`

Trả về các trường mà một điều kiện có thể tham chiếu, được nhóm theo
`trigger_action` và phần. Dùng endpoint này cho condition builder và bản xem
trước phía client.

Mỗi trường có `name` và `type`. Các khóa tùy chọn:

- `enum` (string\[]): Các giá trị được phép của trường.
- `ref` (string): Thực thể mà trường tham chiếu đến. Hãy hiển thị bộ chọn cho nó. Xem
  [Trường tham chiếu](#reference-fields).
- `deprecated` (boolean): Vẫn được đánh giá cho các quy tắc hiện có. Hãy ẩn nó khỏi trình tạo quy tắc mới.

**Request** `GET /policy/schema`

```bash
curl -X GET https://api.fystack.io/api/v1/policy/schema \
  -H "ACCESS-API-KEY: your_api_key" \
  -H "ACCESS-TIMESTAMP: 1667836889" \
  -H "ACCESS-SIGN: YourBase64EncodedSignature=="
```

```json
{
  "success": true,
  "message": "success",
  "code": 0,
  "data": {
    "withdrawal.create": {
      "principal": [
        { "name": "user_email", "type": "string", "deprecated": true },
        { "name": "user_id", "type": "string", "ref": "workspace_user" },
        { "name": "role", "type": "string", "enum": ["owner", "admin", "signer", "proposer", "viewer"] },
        { "name": "initiator_type", "type": "string", "enum": ["user", "api_key"] },
        { "name": "api_key_id", "type": "string", "ref": "api_key" }
      ],
      "withdrawal": [
        { "name": "amount", "type": "number" },
        { "name": "value_usd", "type": "number" },
        { "name": "asset_symbol", "type": "string", "ref": "asset_symbol" },
        { "name": "asset_is_native", "type": "boolean" },
        { "name": "asset_is_known", "type": "boolean" },
        { "name": "token_address", "type": "string" },
        { "name": "destination_address", "type": "string" },
        { "name": "network_code", "type": "string", "ref": "network" },
        { "name": "is_whitelisted", "type": "boolean" },
        { "name": "address_age_sec", "type": "number" },
        { "name": "address_book_id", "type": "string", "ref": "address_book" },
        { "name": "destination_is_internal", "type": "boolean" },
        { "name": "destination_wallet_id", "type": "string", "ref": "wallet" }
      ],
      "wallet": [
        { "name": "id", "type": "string", "ref": "wallet" },
        { "name": "purpose", "type": "string", "enum": ["general", "custody", "payment", "user", "one_time_use", "gas_tank", "deployment"] },
        { "name": "type", "type": "string", "enum": ["standard", "mpc"] },
        { "name": "outflow_1h", "type": "number" },
        { "name": "outflow_6h", "type": "number" },
        { "name": "outflow_24h", "type": "number" },
        { "name": "withdrawal_count_1h", "type": "integer" },
        { "name": "pending_outflow", "type": "number" },
        { "name": "projected_outflow_24h", "type": "number" },
        { "name": "asset_projected_outflow_24h", "type": "number" }
      ],
      "workspace": [
        { "name": "outflow_1h", "type": "number" },
        { "name": "outflow_6h", "type": "number" },
        { "name": "outflow_24h", "type": "number" },
        { "name": "withdrawal_count_1h", "type": "integer" },
        { "name": "network_outflow_1h", "type": "number" },
        { "name": "network_outflow_6h", "type": "number" },
        { "name": "network_outflow_24h", "type": "number" },
        { "name": "network_withdrawal_count_1h", "type": "integer" },
        { "name": "pending_outflow", "type": "number" },
        { "name": "projected_outflow_24h", "type": "number" },
        { "name": "network_pending_outflow", "type": "number" },
        { "name": "network_projected_outflow_24h", "type": "number" },
        { "name": "initiator_projected_outflow_24h", "type": "number" }
      ],
      "context": [
        { "name": "hour", "type": "integer" },
        { "name": "day_of_week", "type": "string" }
      ]
    },
    "web3.transfer": {
      "principal": [ "... same as withdrawal.create ..." ],
      "withdrawal": [ "... same as withdrawal.create ..." ],
      "wallet": [
        { "name": "id", "type": "string", "ref": "wallet" },
        { "name": "purpose", "type": "string", "enum": ["general", "custody", "payment", "user", "one_time_use", "gas_tank", "deployment"] },
        { "name": "type", "type": "string", "enum": ["standard", "mpc"] }
      ],
      "context": [ "... same as withdrawal.create ..." ]
    },
    "web3.contract_call": {
      "principal": [ "... same as withdrawal.create ..." ],
      "resource": [
        { "name": "network_code", "type": "string", "ref": "network" },
        { "name": "contract_address", "type": "string" },
        { "name": "method_selector", "type": "string" },
        { "name": "method_name", "type": "string" },
        { "name": "value_wei", "type": "string" },
        { "name": "gas_limit", "type": "integer" },
        { "name": "decoded_args", "type": "map" }
      ],
      "wallet": [ "... id, purpose, type ..." ],
      "context": [ "... same as withdrawal.create ..." ]
    },
    "web3.sign_message": {
      "principal": [ "... same as withdrawal.create ..." ],
      "resource": [
        { "name": "method", "type": "string", "enum": ["personal_sign", "eth_sign", "eth_signTypedData_v4"] },
        { "name": "network_code", "type": "string", "ref": "network" },
        { "name": "typed_data_primary_type", "type": "string" },
        { "name": "typed_data_domain_name", "type": "string" },
        { "name": "typed_data_verifying_contract", "type": "string" },
        { "name": "is_permit", "type": "boolean" },
        { "name": "permit_spender", "type": "string" },
        { "name": "permit_tokens", "type": "string[]" },
        { "name": "permit_amount_is_unlimited", "type": "boolean" },
        { "name": "permit_deadline", "type": "integer" }
      ],
      "wallet": [ "... id, purpose, type ..." ],
      "context": [ "... same as withdrawal.create ..." ]
    }
  }
}
```

## Xác thực quy tắc

**Endpoint:** `POST /workspaces/{workspace_id}/policies/rules/validate`

Xác thực nội dung quy tắc mà không tạo hoặc cập nhật quy tắc.

### Tham số đường dẫn

- `workspace_id` (string): UUID của workspace.

### Tham số body

- `trigger_action` (string, required): Một trong `withdrawal.create`, `web3.transfer`, `web3.contract_call` hoặc `web3.sign_message`.
- `condition` (string, required): Từ 1 đến 4000 ký tự. Phải biên dịch được thành biểu thức boolean.
- `effect` (string, required): Một trong `ALLOW` hoặc `DENY`. Quy tắc `web3.sign_message` chỉ hỗ trợ từ chối.

### Dữ liệu phản hồi

- `valid` (boolean): `true` khi nội dung quy tắc hợp lệ.

**Request** `POST /workspaces/{workspace_id}/policies/rules/validate`

```bash
curl -X POST https://api.fystack.io/api/v1/workspaces/{workspace_id}/policies/rules/validate \
  -H "ACCESS-API-KEY: your_api_key" \
  -H "ACCESS-TIMESTAMP: 1667836889" \
  -H "ACCESS-SIGN: YourBase64EncodedSignature==" \
  -H "Content-Type: application/json" \
  -d '{
    "trigger_action": "withdrawal.create",
    "condition": "withdrawal.value_usd > 10000",
    "effect": "DENY"
  }'
```

```json
{
  "success": true,
  "message": "success",
  "code": 0,
  "data": { "valid": true }
}
```

## Tạo chính sách

**Endpoint:** `POST /workspaces/{workspace_id}/policies`

Tạo một thay đổi chính sách.

### Tham số đường dẫn

- `workspace_id` (string): UUID của workspace.

### Tham số body

- `name` (string, required): Từ 3 đến 100 ký tự.
- `description` (string): Tùy chọn. Tối đa 500 ký tự.
- `approval_group_id` (string, required): UUID của nhóm phê duyệt.
- `wallet_ids` (string\[]): Tùy chọn. Tối đa 500 UUID ví.
- `rules` (PolicyRuleCreate\[]): Tùy chọn. Tối đa 50 quy tắc.

**Request** `POST /workspaces/{workspace_id}/policies`

```bash
curl -X POST https://api.fystack.io/api/v1/workspaces/{workspace_id}/policies \
  -H "ACCESS-API-KEY: your_api_key" \
  -H "ACCESS-TIMESTAMP: 1667836889" \
  -H "ACCESS-SIGN: YourBase64EncodedSignature==" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Large withdrawal guard",
    "approval_group_id": "a1b2c3d4-e5f6-7890-1234-567890abcdef",
    "wallet_ids": [],
    "rules": [
      {
        "trigger_action": "withdrawal.create",
        "condition": "withdrawal.value_usd > 10000",
        "effect": "DENY"
      }
    ]
  }'
```

```json
{
  "success": true,
  "message": "success",
  "code": 0,
  "data": {
    "status": "pending_approval",
    "approval_request_id": "b7e2a1c4-9d8f-4a3b-8c1d-2e3f4a5b6c7d",
    "policy": {
      "id": "9c8b7a6d-5e4f-3210-9a8b-7c6d5e4f3210",
      "name": "Large withdrawal guard",
      "status": "pending",
      "version": 1,
      "wallet_ids": []
    }
  }
}
```

## Liệt kê chính sách

**Endpoint:** `GET /workspaces/{workspace_id}/policies`

Trả về các chính sách trong một workspace.

### Tham số đường dẫn

- `workspace_id` (string): UUID của workspace.

### Tham số truy vấn

- `status` (string): Tùy chọn. Một trong `pending`, `rejected`, `active` hoặc `inactive`.
- `limit` (integer): Tùy chọn. Tối đa `1000`.
- `offset` (integer): Tùy chọn. Tối đa `100000`.

### Dữ liệu phản hồi

- `data` (Policy\[]): Mảng các đối tượng chính sách.

**Request** `GET /workspaces/{workspace_id}/policies`

```bash
curl -X GET "https://api.fystack.io/api/v1/workspaces/{workspace_id}/policies?status=active&limit=20&offset=0" \
  -H "ACCESS-API-KEY: your_api_key" \
  -H "ACCESS-TIMESTAMP: 1667836889" \
  -H "ACCESS-SIGN: YourBase64EncodedSignature=="
```

## Lấy một chính sách

**Endpoint:** `GET /workspaces/{workspace_id}/policies/{policy_id}`

Trả về một chính sách.

### Tham số đường dẫn

- `workspace_id` (string): UUID của workspace.
- `policy_id` (string): UUID của chính sách.

### Dữ liệu phản hồi

- `data` (Policy): Đối tượng chính sách, bao gồm quy tắc, nhóm phê duyệt và yêu cầu phê duyệt đang chờ nếu có.

**Request** `GET /workspaces/{workspace_id}/policies/{policy_id}`

```bash
curl -X GET https://api.fystack.io/api/v1/workspaces/{workspace_id}/policies/{policy_id} \
  -H "ACCESS-API-KEY: your_api_key" \
  -H "ACCESS-TIMESTAMP: 1667836889" \
  -H "ACCESS-SIGN: YourBase64EncodedSignature=="
```

## Cập nhật chính sách

**Endpoint:** `PUT /workspaces/{workspace_id}/policies/{policy_id}`

Cập nhật các trường của chính sách.

### Tham số đường dẫn

- `workspace_id` (string): UUID của workspace.
- `policy_id` (string): UUID của chính sách.

### Tham số body

- `name` (string): Tùy chọn. Từ 3 đến 100 ký tự.
- `description` (string): Tùy chọn. Tối đa 500 ký tự.
- `approval_group_id` (string): UUID của nhóm phê duyệt, tùy chọn.
- `wallet_ids` (string\[]): Tùy chọn. Tối đa 500 UUID ví. Gửi mảng rỗng để áp dụng cho tất cả các ví.
- `rules` (PolicyRuleCreate\[]): Tùy chọn. Thay thế toàn bộ tập quy tắc nếu có. Gửi mảng rỗng để xóa tất cả quy tắc.

**Request** `PUT /workspaces/{workspace_id}/policies/{policy_id}`

```bash
curl -X PUT https://api.fystack.io/api/v1/workspaces/{workspace_id}/policies/{policy_id} \
  -H "ACCESS-API-KEY: your_api_key" \
  -H "ACCESS-TIMESTAMP: 1667836889" \
  -H "ACCESS-SIGN: YourBase64EncodedSignature==" \
  -H "Content-Type: application/json" \
  -d '{
    "description": "Updated policy description",
    "wallet_ids": ["e0851607-417a-475a-b399-5f3aa262b81d"]
  }'
```

## Xóa chính sách

**Endpoint:** `DELETE /workspaces/{workspace_id}/policies/{policy_id}`

Xóa một chính sách hoặc tạo một thay đổi xóa đang chờ phê duyệt.

### Tham số đường dẫn

- `workspace_id` (string): UUID của workspace.
- `policy_id` (string): UUID của chính sách.

### Dữ liệu phản hồi

- `data` (Mutation response): Phản hồi thay đổi chính sách.

**Request** `DELETE /workspaces/{workspace_id}/policies/{policy_id}`

```bash
curl -X DELETE https://api.fystack.io/api/v1/workspaces/{workspace_id}/policies/{policy_id} \
  -H "ACCESS-API-KEY: your_api_key" \
  -H "ACCESS-TIMESTAMP: 1667836889" \
  -H "ACCESS-SIGN: YourBase64EncodedSignature=="
```

## Lấy lịch sử chính sách

**Endpoint:** `GET /workspaces/{workspace_id}/policies/{policy_id}/history`

Trả về các bản sửa đổi của một chính sách.

### Tham số đường dẫn

- `workspace_id` (string): UUID của workspace.
- `policy_id` (string): UUID của chính sách.

### Dữ liệu phản hồi

- `data` (PolicyRevision\[]): Mảng các bản sửa đổi chính sách, bao gồm `changes` ở cấp trường nếu có.

**Request** `GET /workspaces/{workspace_id}/policies/{policy_id}/history`

```bash
curl -X GET https://api.fystack.io/api/v1/workspaces/{workspace_id}/policies/{policy_id}/history \
  -H "ACCESS-API-KEY: your_api_key" \
  -H "ACCESS-TIMESTAMP: 1667836889" \
  -H "ACCESS-SIGN: YourBase64EncodedSignature=="
```

## Lấy danh sách ví của chính sách

**Endpoint:** `GET /workspaces/{workspace_id}/policies/{policy_id}/wallets`

Trả về chính sách cùng `wallet_ids` hiện tại của nó.

### Tham số đường dẫn

- `workspace_id` (string): UUID của workspace.
- `policy_id` (string): UUID của chính sách.

### Dữ liệu phản hồi

- `data` (Policy): Đối tượng chính sách.

**Request** `GET /workspaces/{workspace_id}/policies/{policy_id}/wallets`

```bash
curl -X GET https://api.fystack.io/api/v1/workspaces/{workspace_id}/policies/{policy_id}/wallets \
  -H "ACCESS-API-KEY: your_api_key" \
  -H "ACCESS-TIMESTAMP: 1667836889" \
  -H "ACCESS-SIGN: YourBase64EncodedSignature=="
```

## Cập nhật danh sách ví của chính sách

**Endpoint:** `PUT /workspaces/{workspace_id}/policies/{policy_id}/wallets`

Thay thế danh sách ví mục tiêu của một chính sách.

### Tham số đường dẫn

- `workspace_id` (string): UUID của workspace.
- `policy_id` (string): UUID của chính sách.

### Tham số body

- `wallet_ids` (string\[]): Tùy chọn. Tối đa 500 UUID ví. Gửi mảng rỗng để áp dụng cho tất cả các ví.

**Request** `PUT /workspaces/{workspace_id}/policies/{policy_id}/wallets`

```bash
curl -X PUT https://api.fystack.io/api/v1/workspaces/{workspace_id}/policies/{policy_id}/wallets \
  -H "ACCESS-API-KEY: your_api_key" \
  -H "ACCESS-TIMESTAMP: 1667836889" \
  -H "ACCESS-SIGN: YourBase64EncodedSignature==" \
  -H "Content-Type: application/json" \
  -d '{ "wallet_ids": ["e0851607-417a-475a-b399-5f3aa262b81d"] }'
```

## Tạo quy tắc chính sách

**Endpoint:** `POST /workspaces/{workspace_id}/policies/{policy_id}/rules`

Tạo một quy tắc trong một chính sách có sẵn.

### Tham số đường dẫn

- `workspace_id` (string): UUID của workspace.
- `policy_id` (string): UUID của chính sách.

### Tham số body

- `id` (string): UUID của quy tắc, tùy chọn.
- `trigger_action` (string, required): Một trong `withdrawal.create`, `web3.transfer`, `web3.contract_call` hoặc `web3.sign_message`.
- `condition` (string, required): Từ 1 đến 4000 ký tự.
- `effect` (string, required): Một trong `ALLOW` hoặc `DENY`. Quy tắc `web3.sign_message` chỉ hỗ trợ từ chối.
- `description` (string): Tùy chọn. Tối đa 500 ký tự.
- `is_enabled` (boolean): Tùy chọn. Mặc định là `true`.

**Request** `POST /workspaces/{workspace_id}/policies/{policy_id}/rules`

```bash
curl -X POST https://api.fystack.io/api/v1/workspaces/{workspace_id}/policies/{policy_id}/rules \
  -H "ACCESS-API-KEY: your_api_key" \
  -H "ACCESS-TIMESTAMP: 1667836889" \
  -H "ACCESS-SIGN: YourBase64EncodedSignature==" \
  -H "Content-Type: application/json" \
  -d '{
    "trigger_action": "web3.contract_call",
    "condition": "resource.gas_limit > 100000",
    "effect": "DENY",
    "is_enabled": true
  }'
```

## Cập nhật quy tắc chính sách

**Endpoint:** `PUT /workspaces/{workspace_id}/policies/rules/{rule_id}`

Cập nhật các trường có thể thay đổi của quy tắc. Trigger action là bất biến,
hãy xóa và tạo lại quy tắc để thay đổi nó.

### Tham số đường dẫn

- `workspace_id` (string): UUID của workspace.
- `rule_id` (string): UUID của quy tắc.

### Tham số body

- `condition` (string): Tùy chọn. Từ 1 đến 4000 ký tự.
- `effect` (string): Tùy chọn. Một trong `ALLOW` hoặc `DENY`.
- `description` (string): Tùy chọn. Tối đa 500 ký tự.
- `is_enabled` (boolean): Tùy chọn.

**Request** `PUT /workspaces/{workspace_id}/policies/rules/{rule_id}`

```bash
curl -X PUT https://api.fystack.io/api/v1/workspaces/{workspace_id}/policies/rules/{rule_id} \
  -H "ACCESS-API-KEY: your_api_key" \
  -H "ACCESS-TIMESTAMP: 1667836889" \
  -H "ACCESS-SIGN: YourBase64EncodedSignature==" \
  -H "Content-Type: application/json" \
  -d '{
    "condition": "resource.gas_limit > 150000",
    "is_enabled": true
  }'
```

## Xóa quy tắc chính sách

**Endpoint:** `DELETE /workspaces/{workspace_id}/policies/rules/{rule_id}`

Xóa một quy tắc chính sách hoặc tạo một thay đổi xóa quy tắc đang chờ phê duyệt.

### Tham số đường dẫn

- `workspace_id` (string): UUID của workspace.
- `rule_id` (string): UUID của quy tắc.

### Dữ liệu phản hồi

- `data` (Mutation response): Phản hồi thay đổi quy tắc.

**Request** `DELETE /workspaces/{workspace_id}/policies/rules/{rule_id}`

```bash
curl -X DELETE https://api.fystack.io/api/v1/workspaces/{workspace_id}/policies/rules/{rule_id} \
  -H "ACCESS-API-KEY: your_api_key" \
  -H "ACCESS-TIMESTAMP: 1667836889" \
  -H "ACCESS-SIGN: YourBase64EncodedSignature=="
```

## Mẫu thiết kế

Dùng quy tắc `DENY` cho các biện pháp kiểm soát cứng: danh sách trừng phạt, người nhận không xác định, mục sổ địa chỉ mới, giới hạn dòng tiền ra dự báo, token không xác định, permit không giới hạn hoặc các phương thức hợp đồng rủi ro cao.

Dùng quy tắc `ALLOW` một cách hạn chế. `ALLOW` khớp sẽ bỏ qua phê duyệt, nên điều kiện cần chính xác: giá trị USD thấp, bên khởi tạo đáng tin cậy, ví mục tiêu đã biết, mạng lưới đã biết, và người nhận đã biết kèm kiểm tra tuổi địa chỉ, hoặc hợp đồng và phương thức đã biết.

Kết hợp mỗi `ALLOW` với một mức trần `DENY`, chẳng hạn `wallet.projected_outflow_24h` hoặc `workspace.initiator_projected_outflow_24h`. Vì `DENY` luôn được ưu tiên, mức trần này cũng giới hạn luồng tự động phê duyệt.

Giữ các tập chính sách nhỏ và rõ ràng. Chính sách rộng trên toàn workspace hữu ích cho các biện pháp kiểm soát cơ bản, còn chính sách theo phạm vi ví phù hợp hơn khi ví nóng, ví ngân quỹ hoặc ví khách hàng có ngưỡng rủi ro khác nhau.

Xem [Mẫu chính sách](https://docs.fystack.io/product/policies.md#policy-templates) để có các ví dụ đầy đủ.
