Hướng dẫn AgentFlow

Ví dụ: hồ sơ

Tạo, truy vấn và đếm hồ sơ; sửa một vài trường bằng expected_updated_at; xóa; và khởi chạy một lượt chạy hàng loạt trên nhiều hồ sơ.

Các lệnh dưới đây gọi API với tư cách một chủ thể dịch vụ:

export ORIGIN=https://agentflow.example.com
export AGENTFLOW_KEY=afk_…
export ENTITY_ID=0a5f…

Phản hồi đã được rút gọn; … đánh dấu phần lược bỏ. Khóa trường (tieu_de, so_tien, trang_thai) là của một thực thể minh họa — hãy dùng khóa trường của thực thể bạn. Những gì khóa đọc và ghi được tuân theo vai trò, phạm vi quyền của khóa và quyền truy cập trên thực thể.

1. Xem biểu mẫu tạo hồ sơ

Hồ sơ được tạo qua biểu mẫu tạo đã cấu hình cho thực thể:

curl -sS "$ORIGIN/api/v1/entities/$ENTITY_ID/create-form" \
  -H "Authorization: Bearer $AGENTFLOW_KEY"
{
  "form_definition_id": "b813…",
  "schema_json": { "properties": { "tieu_de": { … }, "so_tien": { … } }, … },
  "ui_schema_json": { … },
  "sensitive_field_paths": [],
  "form_updated_at": "2026-08-30T02:41:09.118204Z",
  …
}

Thực thể không có biểu mẫu tạo thì trả 404.

2. Tạo hồ sơ

curl -sS -X POST "$ORIGIN/api/v1/entities/$ENTITY_ID/records" \
  -H "Authorization: Bearer $AGENTFLOW_KEY" \
  -H "Content-Type: application/json" \
  -d '{"form_payload": {"tieu_de": "PO-1001", "so_tien": 12500000}}'

201 Created:

{
  "id": "7d2e…",
  "entity_id": "0a5f…",
  "body": { "tieu_de": "PO-1001", "so_tien": 12500000, "trang_thai": "cho_duyet" },
  "created_at": "2026-09-12T08:20:11.093114Z",
  "updated_at": "2026-09-12T08:20:11.093114Z",
  …
}
  • form_payload theo khóa trường của biểu mẫu tạo.
  • Với thực thể phân loại theo đơn vị, thêm unit_id để chọn đơn vị. Bỏ trống thì hồ sơ vào đơn vị chính của người gọi; một null tường minh bị từ chối.
  • Trường nhạy cảm bị lược khỏi body trả về, trừ khi người gọi được một hồ sơ bảo mật trường cấp quyền xem trường đó.
  • Không qua kiểm tra thì trả 422, với field_errors nêu từng trường.

Gửi lại mà không tạo hai hồ sơ

Gửi kèm một Idempotency-Key. Nếu không chắc yêu cầu đã tới server — hết thời gian chờ, mất kết nối — hãy gửi lại đúng lệnh đó, với cùng khóa:

export IDEMPOTENCY_KEY=$(uuidgen)

curl -sS -i -X POST "$ORIGIN/api/v1/entities/$ENTITY_ID/records" \
  -H "Authorization: Bearer $AGENTFLOW_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $IDEMPOTENCY_KEY" \
  -d '{"form_payload": {"tieu_de": "PO-1001", "so_tien": 12500000}}'

Khi hồ sơ đã được tạo ở lần trước, lần gửi lại trả:

HTTP/1.1 201 Created
Content-Type: application/json
Idempotent-Replayed: true

{ "id": "7d2e…", "body": { "tieu_de": "PO-1001", "so_tien": 12500000, … }, … }
  • Cùng id với lần trước: không có hồ sơ thứ hai. Hồ sơ được trả về như hiện tại.
  • Cùng khóa nhưng đổi form_payload: 422 IDEMPOTENCY_KEY_MISMATCH, và không có gì được tạo. Việc khác thì dùng khóa mới.
  • Chi tiết nằm ở Thử lại an toàn.

3. Truy vấn hồ sơ

curl -sS -X POST "$ORIGIN/api/v1/entities/$ENTITY_ID/records/query" \
  -H "Authorization: Bearer $AGENTFLOW_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "filter": {
      "q": "PO-",
      "field_filters": [
        { "field": "trang_thai", "op": "eq", "value": "cho_duyet" },
        { "field": "so_tien", "op": "gte", "value": 10000000 }
      ]
    },
    "sort": "updated_at",
    "dir": "desc",
    "limit": 50
  }'
{
  "items": [
    { "id": "7d2e…", "body": { "tieu_de": "PO-1001", … }, "updated_at": "2026-09-12T08:20:11.093114Z", … }
  ],
  "next_cursor": "…",
  "prev_cursor": null
}
  • Mỗi điều kiện trong field_filters là {field, op, value}. Các op thường dùng: eq, ne, gt, gte, lt, lte, between (giá trị là mảng [từ, đến]), in và not_in (giá trị là mảng), contains, not_contains, starts_with, ends_with, is_empty và is_not_empty (không có giá trị), within (một khoảng ngày như today, last_7_days, this_month, this_quarter, this_year, chỉ trên trường ngày).
  • sort là khóa một trường, hoặc updated_at / created_at.
  • Trang kế tiếp: gửi lại cùng thân yêu cầu, thêm "cursor": "<next_cursor>". Xem Phân trang.
  • Thực thể không cho duyệt hồ sơ trả 403 ENTITY_NOT_BROWSABLE. Lọc hoặc sắp xếp trên một trường nhạy cảm trả 403 ENTITY_SENSITIVE_FILTER_DENIED, kèm tên trường, trừ khi người gọi được một hồ sơ bảo mật trường cấp quyền xem trường đó.

4. Đếm hồ sơ

curl -sS -X POST "$ORIGIN/api/v1/entities/$ENTITY_ID/records/count" \
  -H "Authorization: Bearer $AGENTFLOW_KEY" \
  -H "Content-Type: application/json" \
  -d '{"filter": {"field_filters": [{"field": "trang_thai", "op": "eq", "value": "cho_duyet"}]}}'
{ "count": 12, "capped": false }

Con số tính trong phạm vi của người gọi. capped: true nghĩa là số thật lớn hơn hoặc bằng count.

5. Sửa một vài trường

PATCH chỉ đổi những trường bạn gửi, và cần expected_updated_at — giá trị updated_at của hồ sơ lúc bạn đọc nó:

curl -sS -X PATCH "$ORIGIN/api/v1/entities/$ENTITY_ID/records/$RECORD_ID" \
  -H "Authorization: Bearer $AGENTFLOW_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "changes": { "trang_thai": "da_duyet" },
    "expected_updated_at": "2026-09-12T08:20:11.093114Z"
  }'
{
  "id": "7d2e…",
  "body": { "tieu_de": "PO-1001", "so_tien": 12500000, "trang_thai": "da_duyet" },
  "updated_at": "2026-09-12T09:02:37.550981Z",
  …
}
  • changes theo khóa trường của thực thể. Trường không gửi thì giữ nguyên; gửi null là xóa giá trị.
  • Một khóa trường không tồn tại: 422 ENTITY_FIELD_NOT_FOUND.
  • Hồ sơ đã đổi kể từ lúc bạn đọc: 409 STALE_VERSION. Hãy đọc lại hồ sơ (GET /api/v1/entities/{entity_id}/records/{record_id}), áp lại thay đổi với updated_at mới rồi gửi lại.
  • Muốn thay theo biểu mẫu sửa thay vì từng trường, dùng PUT cùng đường dẫn với form_payload và expected_updated_at.
  • PATCH cũng nhận Idempotency-Key. Lần phát lại không kiểm tra lại expected_updated_at, nên không trả 409 STALE_VERSION dù hồ sơ đã đổi sau đó.

6. Xóa hồ sơ

expected_updated_at đi trong chuỗi truy vấn:

curl -sS -X DELETE -G "$ORIGIN/api/v1/entities/$ENTITY_ID/records/$RECORD_ID" \
  -H "Authorization: Bearer $AGENTFLOW_KEY" \
  --data-urlencode "expected_updated_at=2026-09-12T09:02:37.550981Z"

Thành công trả 204 No Content. Hồ sơ đã đổi kể từ lúc bạn đọc: 409 STALE_VERSION.

7. Khởi chạy lượt chạy hàng loạt

Chạy một quy trình gắn với hồ sơ trên nhiều hồ sơ của thực thể cùng lúc:

curl -sS -X POST "$ORIGIN/api/v1/entities/$ENTITY_ID/records/batch-runs" \
  -H "Authorization: Bearer $AGENTFLOW_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "workflow_id": "3f6c…",
    "target": { "kind": "ids", "ids": ["7d2e…", "91ac…", "c3b0…"] }
  }'

202 Accepted — lượt chạy hàng loạt được giải quyết và khởi động các lượt chạy ở nền:

{
  "id": "e5d1…",
  "entity_id": "0a5f…",
  "workflow_id": "3f6c…",
  "version_id": "a91d…",
  "arity": "single",
  "status": "…",
  "failure_code": null,
  "failure_detail": null,
  "created_at": "2026-09-12T09:10:48.204417Z",
  …
}
  • target là danh sách id ({"kind": "ids", "ids": [...]}, tối đa 200 id) hoặc một bộ lọc ({"kind": "query", "raw_filter": {"filter": {...}}}).
  • params (không bắt buộc) mang dữ liệu cho quy trình.
  • arity là single khi quy trình chạy riêng trên từng hồ sơ, multiple khi một lượt chạy nhận cả tập hồ sơ.
  • Lệnh này cũng nhận Idempotency-Key: gửi lại với cùng khóa trả 202 với cùng lượt chạy hàng loạt, không khởi chạy lần hai.

Theo dõi tiến độ:

curl -sS "$ORIGIN/api/v1/entities/$ENTITY_ID/records/batch-runs/$BATCH_RUN_ID" \
  -H "Authorization: Bearer $AGENTFLOW_KEY"
{
  "arity": "single",
  "header": { "id": "e5d1…", "status": "…", … },
  "counts": { "pending": 0, "started": 2, "failed": 1, "skipped": 0 },
  "members": [
    { "ordinal": 1, "record_id": "7d2e…", "status": "…", "instance_id": "c04b…", "error_code": null, "failure_detail": null },
    …
  ]
}
  • Với arity: "single", phản hồi có counts và 50 thành viên đầu tiên theo ordinal. Với arity: "multiple", phản hồi có member_count và set_run (instance_id, status) của lượt chạy nhận cả tập; set_run là null khi chưa có lượt chạy đó.
  • skipped được đếm riêng với failed.
  • Toàn bộ danh sách thành viên nằm ở GET …/batch-runs/{batch_run_id}/members. Nó trả về {items, next_cursor, prev_cursor} và phân trang bằng limit (từ 1 đến 200, mặc định 50), cursor và before như mọi danh sách khác. Xem Phân trang.
  • Thành viên sắp xếp theo ordinal, tăng dần khi không gửi dir. Một q là id hồ sơ thì khớp đúng hồ sơ đó; chuỗi khác khớp phần đầu của error_code, không phân biệt hoa thường — cách nhanh để tìm những thành viên thất bại vì cùng một lý do.

On this page