对外集成

对外 API v1

Base URL:/flowcraft/api/v1。所有请求需请求头 Authorization: Bearer <JWT>(HS256 + app_secret 本地签发,payload 含 app_idiatexp,最长 1 小时)。 管理员在 接口授权 创建 App 并配置模块权限。每个 App 绑定创建时所在空间,详见下方「空间隔离」。

空间隔离

每个 App 在创建时 绑定管理员所在空间。JWT 认证通过后,服务端以该空间作为数据边界。

规则说明
数据范围所有 v1 读写仅涉及该空间内的 users、organizations、workflows / journeys、attachments
跨空间访问其他空间的资源 ID 请求返回 404(非 403)
创建用户POST /users 新用户自动归属凭证空间;role 不可设为空间管理员(super_admin
多空间部署需在各空间分别创建 App 与凭证;JWT payload 格式不变,无需额外传 namespace_id

集成方无需修改 JWT 签发逻辑,但须知晓:同一 app_id 只能访问创建时绑定的单一空间数据。

认证与通用参数

参数中文名称位置必填说明
Authorization访问凭证请求头Bearer <JWT>,唯一认证方式;无效或过期返回 401
Accept接受类型请求头建议 application/json
Content-Type内容类型请求头提交 JSON 时必填须为 application/json
page页码Query列表页码,从 1 开始,默认第 1 页
per_page每页条数Query每页返回的记录数量

列表响应头:X-FLOWCRAFT-Current-Page(当前页)、X-FLOWCRAFT-Total-Pages(总页数)、X-FLOWCRAFT-Total-Count(总条数)。

错误体格式:{ "errors": ["说明"] }。常见状态码:200/201 成功,204 删除成功,401 凭证无效,403 无模块权限或流程未发布,404 资源不存在,422 校验失败。

JWT Payload 示例(HS256 签名,密钥为 app_secret;exp − iat 不得超过 3600 秒)

{
  "app_id": "fc_a1b2c3d4",
  "iat": 1783130400,
  "exp": 1783134000
}

签名后放入请求头

Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.xxxxx.yyyyy
模块权限允许操作
组织查询获取列表、查看详情
组织新增与修改新建组织、修改名称或上级
组织删除删除叶子组织
用户查询获取列表、查看详情
用户新增与修改新建用户、修改资料
用户删除删除用户
流程图新建创建流程并一次性声明整张图
流程图修改修改已有流程的图、字段与发起限制
流程记录查询指定流程下的列表与详情
流程记录发起在已发布流程上发起新记录
附件读取下载已上传的附件
附件上传上传文件并获取 signed_id

下文示例基于同一套「请假审批」场景:流程 id=3(节点 begin 发起 → approve_1 部门审批 → approve_2 人事备案 → end 结束,表单字段 reason 请假事由 / days 请假天数);组织「总部 id=1」→「研发部 id=5」;用户「张三 id=42(发起人)」「李四 id=43(部门审批人)」「王五 id=44(人事备案)」。

组织接口

模块「组织」:查询、新增与修改、删除权限分别对应下列操作。

GET /api/v1/organizations

分页列出组织,支持按名称搜索、按上级筛选直接子组织。需「组织 · 查询」权限。

参数中文名称位置必填说明
q搜索关键词Query按组织名称模糊搜索
parent_id上级组织编号Query仅返回该组织的直接子组织(不含孙级);上级不存在时返回空列表
page页码Query分页页码,从 1 开始
per_page每页条数Query每页返回的组织数量

请求示例

GET /flowcraft/api/v1/organizations?q=研发&page=1
Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.xxxxx.yyyyy
Accept: application/json

响应示例 200(ancestry 为内部祖先路径格式,建议使用 parent_id / ancestry_path)

[
  {
    "id": 1,
    "name": "总部",
    "ancestry": null,
    "ancestry_depth": 0,
    "created_at": "2026-01-05T10:00:00.000+08:00",
    "updated_at": "2026-01-05T10:00:00.000+08:00",
    "parent_id": null,
    "children_count": 3
  },
  {
    "id": 5,
    "name": "研发部",
    "ancestry": "1",
    "ancestry_depth": 1,
    "created_at": "2026-01-06T09:20:00.000+08:00",
    "updated_at": "2026-03-12T15:40:00.000+08:00",
    "parent_id": 1,
    "children_count": 0
  }
]

GET /api/v1/organizations/:id

获取单个组织详情,比列表多 members_count(成员数)与 ancestry_path(祖先名称路径)。需「组织 · 查询」权限;组织不存在返回 404。

参数中文名称位置必填说明
id组织编号路径要查看的组织 ID

请求示例

GET /flowcraft/api/v1/organizations/5
Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.xxxxx.yyyyy
Accept: application/json

响应示例 200

{
  "id": 5,
  "name": "研发部",
  "ancestry": "1",
  "ancestry_depth": 1,
  "created_at": "2026-01-06T09:20:00.000+08:00",
  "updated_at": "2026-03-12T15:40:00.000+08:00",
  "parent_id": 1,
  "children_count": 0,
  "members_count": 12,
  "ancestry_path": ["总部", "研发部"]
}

POST /api/v1/organizations

新建组织,可指定上级。需「组织 · 新增与修改」权限。

字段中文名称位置必填说明
organization.name组织名称Body同级兄弟节点下不可重名
organization.parent_id上级组织编号Body省略则创建为根组织;须为已存在的组织 ID

请求示例

POST /flowcraft/api/v1/organizations
Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.xxxxx.yyyyy
Content-Type: application/json

{
  "organization": {
    "name": "研发部",
    "parent_id": 1
  }
}

响应示例 201(结构同详情接口)

{
  "id": 5,
  "name": "研发部",
  "ancestry": "1",
  "ancestry_depth": 1,
  "created_at": "2026-07-03T10:05:00.000+08:00",
  "updated_at": "2026-07-03T10:05:00.000+08:00",
  "parent_id": 1,
  "children_count": 0,
  "members_count": 0,
  "ancestry_path": ["总部", "研发部"]
}

错误示例 422(名称为空、同级重名,或上级不存在)

{ "errors": ["上级组织不存在"] }

PATCH /api/v1/organizations/:id

修改组织名称或调整组织树位置。需「组织 · 新增与修改」权限。

参数/字段中文名称位置必填说明
id组织编号路径要修改的组织 ID
organization.name组织名称Body新的组织名称
organization.parent_id上级组织编号Body移动到新的上级;传空值可升为根组织

请求示例(改名并升为根组织)

PATCH /flowcraft/api/v1/organizations/5
Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.xxxxx.yyyyy
Content-Type: application/json

{
  "organization": {
    "name": "研发中心",
    "parent_id": null
  }
}

响应示例 200

{
  "id": 5,
  "name": "研发中心",
  "ancestry": null,
  "ancestry_depth": 0,
  "created_at": "2026-01-06T09:20:00.000+08:00",
  "updated_at": "2026-07-03T10:10:00.000+08:00",
  "parent_id": null,
  "children_count": 0,
  "members_count": 12,
  "ancestry_path": ["研发中心"]
}

DELETE /api/v1/organizations/:id

删除无子组织的叶子组织。需「组织 · 删除」权限;存在子组织时返回 422。

参数中文名称位置必填说明
id组织编号路径要删除的组织 ID

请求示例(成功时返回 204,无响应体)

DELETE /flowcraft/api/v1/organizations/5
Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.xxxxx.yyyyy

错误示例 422

{ "errors": ["组织存在子组织,无法删除"] }

用户接口

模块「用户」:查询、新增与修改、删除权限分别对应下列操作。返回字段不含密码。

GET /api/v1/users

分页列出用户,支持多条件搜索与按创建时间排序。需「用户 · 查询」权限。

参数中文名称位置必填说明
q搜索关键词Query同时匹配姓名或手机号;若同时传 name 或 phone 则本参数不生效
name姓名Query仅按姓名模糊搜索
phone手机号Query仅按手机号模糊搜索
role角色Query精确过滤:admin(管理员)或 member(普通成员)
direction排序方向Query按创建时间排序,asc 升序 / desc 降序,默认降序
page页码Query分页页码,从 1 开始
per_page每页条数Query每页返回的用户数量

请求示例

GET /flowcraft/api/v1/users?q=张&role=member&direction=desc
Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.xxxxx.yyyyy
Accept: application/json

响应示例 200

[
  {
    "id": 42,
    "name": "张三",
    "phone": "13800000042",
    "role": "member",
    "created_at": "2026-02-10T09:00:00.000+08:00",
    "updated_at": "2026-06-20T11:30:00.000+08:00"
  },
  {
    "id": 43,
    "name": "李四",
    "phone": "13800000043",
    "role": "member",
    "created_at": "2026-02-10T09:05:00.000+08:00",
    "updated_at": "2026-02-10T09:05:00.000+08:00"
  }
]

GET /api/v1/users/:id

获取单个用户详情。需「用户 · 查询」权限;用户不存在返回 404。

参数中文名称位置必填说明
id用户编号路径要查看的用户 ID

请求示例

GET /flowcraft/api/v1/users/42
Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.xxxxx.yyyyy
Accept: application/json

响应示例 200

{
  "id": 42,
  "name": "张三",
  "phone": "13800000042",
  "role": "member",
  "created_at": "2026-02-10T09:00:00.000+08:00",
  "updated_at": "2026-06-20T11:30:00.000+08:00"
}

POST /api/v1/users

新建系统用户。需「用户 · 新增与修改」权限。

字段中文名称位置必填说明
user.name姓名Body用户显示名称
user.phone手机号Body登录账号,全局唯一
user.password密码Body登录密码,至少 6 位
user.role角色Bodyadminmember,默认普通成员

请求示例

POST /flowcraft/api/v1/users
Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.xxxxx.yyyyy
Content-Type: application/json

{
  "user": {
    "name": "张三",
    "phone": "13800000042",
    "password": "secret66",
    "role": "member"
  }
}

响应示例 201

{
  "id": 42,
  "name": "张三",
  "phone": "13800000042",
  "role": "member",
  "created_at": "2026-07-03T10:20:00.000+08:00",
  "updated_at": "2026-07-03T10:20:00.000+08:00"
}

错误示例 422(手机号重复、密码过短、角色非法等)

{ "errors": ["Phone has already been taken"] }

PATCH /api/v1/users/:id

修改用户资料。需「用户 · 新增与修改」权限。

参数/字段中文名称位置必填说明
id用户编号路径要修改的用户 ID
user.name姓名Body新的显示名称
user.phone手机号Body新的登录手机号,须全局唯一
user.password密码Body新密码;留空或不传则保持原密码不变
user.role角色Bodyadminmember

请求示例

PATCH /flowcraft/api/v1/users/42
Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.xxxxx.yyyyy
Content-Type: application/json

{
  "user": {
    "name": "张三丰",
    "role": "admin"
  }
}

响应示例 200

{
  "id": 42,
  "name": "张三丰",
  "phone": "13800000042",
  "role": "admin",
  "created_at": "2026-02-10T09:00:00.000+08:00",
  "updated_at": "2026-07-03T10:25:00.000+08:00"
}

DELETE /api/v1/users/:id

删除用户。需「用户 · 删除」权限;用户仍有关联流程或待办时返回 422。

参数中文名称位置必填说明
id用户编号路径要删除的用户 ID

请求示例(成功时返回 204,无响应体)

DELETE /flowcraft/api/v1/users/42
Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.xxxxx.yyyyy

错误示例 422(仍有关联数据)

{ "errors": ["该用户发起过流程,无法删除"] }

附件接口

模块「附件」:上传返回 signed_id,供流程发起时的附件字段引用;字段级类型/数量限制在保存表单时校验。 单文件默认最大 5MB(ATTACHMENT_MAX_SIZE_MB),单个附件字段最多 20 个文件(ATTACHMENT_MAX_COUNT)。

POST /api/v1/attachments

上传文件。需「附件 · 上传」权限。请求体为 multipart/form-data,非 JSON。

参数中文名称位置必填说明
file文件Bodymultipart 字段名须为 file

请求示例

POST /flowcraft/api/v1/attachments
Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.xxxxx.yyyyy
Content-Type: multipart/form-data

file=@/path/to/report.pdf

响应示例 201

{
  "signed_id": "eyJf...",
  "filename": "report.pdf",
  "content_type": "application/pdf",
  "byte_size": 12345,
  "image": false
}

在流程发起中引用(附件字段 identity_key 为 docs 时)

POST /flowcraft/api/v1/workflows/3/journeys
Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.xxxxx.yyyyy
Content-Type: application/json

{
  "journey": {
    "proposer_id": 42,
    "form_data": {
      "reason": "出差参展",
      "docs": [{ "signed_id": "eyJf..." }]
    }
  }
}

错误示例

422  { "errors": ["请选择文件"] }
422  { "errors": ["文件大小超过 5MB 限制"] }
403  { "errors": ["无权访问该模块"] }

GET /api/v1/attachments/:signed_id

下载或预览附件。需「附件 · 读取」权限。signed_id 来自上传响应或流程详情中的 entry value。

参数中文名称位置必填说明
signed_id附件标识路径上传接口返回的 signed_id
disposition展示方式Queryattachment 强制下载,默认 inline 预览

请求示例

GET /flowcraft/api/v1/attachments/eyJf...?disposition=attachment
Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.xxxxx.yyyyy

响应示例 200

(文件二进制流,Content-Type 为上传时的 content_type)

错误示例

404  { "errors": ["附件不存在或已失效"] }
403  { "errors": ["无权访问该模块"] }

流程图接口

一次请求声明整张流程图:节点、连线、发起字段、节点回传字段、处理人与抄送人、机器节点推送配置、发起限制,全在同一个 workflow 对象里。 「流程图 · 新建」对应 POST,「流程图 · 修改」对应 PATCH,两者权限独立。

本接口只写草稿,不发布。 写入成功后流程仍按原已发布版本运行,响应中的 has_unpublished_changestrue 即表示需要管理员到后台确认发版。 草稿允许处于不完整状态(缺连线、有孤立节点等),结构完整性在人工发布时才校验 —— 写入成功不等于流程可发布。

规则说明
声明式覆盖顶层键缺席 = 不改出现 = 全量覆盖。传了 graph,同层未列出的节点与连线会被删除;传了 fields,未列出的字段会被删除
对齐方式节点与连线按 key 对齐,字段按 identity_key 对齐,选项按 value 对齐。集成方无需知道任何数据库 id
排序字段与选项的 position 取数组下标,按数组顺序排列
起止节点每张图(含子图)都必须包含 key: "start"Vertex::Beginkey: "end"Vertex::End,未列出返回 422 而非静默删除
子图例外child_graphs增量而非全量:未提及的子图保持不变。子图的存亡由子流程节点决定,见下文
原子性整个请求在单个事务内完成,任一步失败全部回滚,不留半写状态
归档流程已归档的流程不可修改,返回 422

POST /api/v1/workflows

新建流程并一次性写入整张图。需「流程图 · 新建」权限。

字段中文名称位置必填说明
workflow.creator_id创建人编号Body本空间内的用户 ID;不存在返回 422
workflow.name流程名称Body流程显示名称
workflow.description流程说明Body流程描述文本
workflow.icon图标Body图标标识
workflow.fields[]发起字段Body发起人填写的表单字段,结构见下方「字段对象」
workflow.graph流程图Bodyvertices / edges / child_graphs;省略则保留默认的 start / end 两节点
workflow.setting发起限制Body发起时段与次数限制,结构见下方「发起限制对象」

请求示例(请假审批:发起 → 部门审批 → 结束)

POST /flowcraft/api/v1/workflows
Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.xxxxx.yyyyy
Content-Type: application/json

{
  "workflow": {
    "creator_id": 42,
    "name": "请假审批",
    "description": "员工请假的标准审批流程",
    "fields": [
      { "type": "Field::Text", "title": "请假事由", "identity_key": "reason", "required": true },
      { "type": "Field::Integer", "title": "请假天数", "identity_key": "days", "required": true, "settings": { "min": 1, "max": 30 } }
    ],
    "graph": {
      "vertices": [
        { "key": "start", "type": "Vertex::Begin", "title": "发起", "position": { "x": 200, "y": 80 },
          "user_boundary": { "assignee_source": "static", "user_ids": [42] } },
        { "key": "approve_1", "type": "Vertex::Normal", "title": "部门审批", "position": { "x": 200, "y": 200 },
          "approval_strategy": "any", "transfer_enabled": true,
          "user_boundary": { "assignee_source": "static", "user_ids": [43] },
          "cc_boundary": { "user_ids": [44], "cc_triggers": ["handle"] },
          "fields": [ { "type": "Field::TextArea", "title": "审批意见", "identity_key": "opinion" } ] },
        { "key": "end", "type": "Vertex::End", "title": "结束", "position": { "x": 200, "y": 320 } }
      ],
      "edges": [
        { "key": "e1", "source_key": "start", "target_key": "approve_1",
          "condition": { "all": [ { "field_identity_key": "days", "op": "gte", "values": [3] } ] } },
        { "key": "e2", "source_key": "approve_1", "target_key": "end" }
      ]
    }
  }
}

响应示例 201(节选;graph 结构与请求同构,另带数据库 id 与边界摘要)

{
  "id": 3,
  "name": "请假审批",
  "status": "draft",
  "creator": { "id": 42, "name": "张三" },
  "latest_version_number": null,
  "fields": [ { "type": "Field::Text", "title": "请假事由", "identity_key": "reason", "required": true, "options": [], "settings": {}, "position": 0 } ],
  "graph": { "id": 8, "vertices": [ "…" ], "edges": [ "…" ] },
  "has_unpublished_changes": true
}

错误示例

403  { "errors": ["无权访问该模块"] }
422  { "errors": ["创建人不存在"] }
422  { "errors": ["不支持的节点类型「Foo」"] }
422  { "errors": ["不能删除Vertex::Begin 节点 start"] }

PATCH /api/v1/workflows/:id

修改已有流程。需「流程图 · 修改」权限。请求体与新建同构(creator_id 除外,创建人不可改);其他空间的流程 ID 返回 404。

请求示例(只改流程名与发起限制,图与字段保持不变)

PATCH /flowcraft/api/v1/workflows/3
Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.xxxxx.yyyyy
Content-Type: application/json

{
  "workflow": {
    "name": "员工请假审批",
    "setting": {
      "proposal_time_limited": true,
      "proposal_time_rules": [ { "type": "workday", "start_time": "09:00", "end_time": "18:00" } ]
    }
  }
}

错误示例

404  流程不存在或不属于本空间
422  { "errors": ["已归档的流程不可编辑"] }

节点对象

节点类型共五种:Vertex::Begin(发起)、Vertex::Normal(处理)、Vertex::End(结束)、Vertex::SubProcess(子流程)、Vertex::Machine(机器节点)。其余取值一律 422。

字段中文名称必填说明
key节点标识同一张图内唯一,连线与子图都按它引用
type节点类型见上方五种取值
title节点名称节点显示名
position画布坐标{ "x": 200, "y": 80 }
user_boundary处理人见下方「人员边界对象」。发起节点上表示谁可发起
cc_boundary抄送人同上,另需 cc_triggers
fields回传字段该节点处理时填写的字段,结构同「字段对象」
automation_agent推送配置仅机器节点:push_url(推送地址)与 push_headers(自定义请求头)
其他语义属性approval_strategyapproval_thresholdparallel_enabledtransfer_enabledcomment_requiredassignee_selection_enableddeadline_enableddelay_request_enabled 等,取值与后台编辑器一致,且只在适用的节点类型上生效

人员边界对象

user_boundary / cc_boundary 一旦出现即为该边界的完整声明:三个人员集合未列出的按空处理。 只想改节点标题而不动处理人时,请整个省略这两个键,不要传空对象。

字段中文名称说明
assignee_source人员来源static 指定人员(默认)、proposer 发起人本人、node 取某个前置节点的处理人
assignee_source_vertex_key来源节点node 来源需要;被引用节点须已存在、为处理节点且在当前节点之前
user_ids人员直接指定的用户 ID 数组
organization_ids组织按组织选人,取组织的直属成员
tag_ids标签按标签选人
tag_mode标签组合union 并集(默认)或 intersection 交集
cc_triggers抄送时机cc_boundaryarrive 到达节点、handle 节点处理后、transfer 转办时。抄送人非空时至少要选一项;各节点类型可用值不同,不适用的会被自动忽略

同样是「传了空的人员集合」,处理节点会返回 422(没人能审批),而发起节点表示全员可发起,是合法配置。

字段对象

identity_key 是字段的稳定标识,必填 —— 修改时按它对齐,发起流程时的 form_data、连线条件与计算字段公式也都按它引用。 字段类型建后不可改,需要换类型请删掉重建。

字段中文名称必填说明
type字段类型Field::Text 单行文本、Field::TextArea 多行文本、Field::Integer 数字、Field::DateTime 日期时间、Field::Phone 手机号、Field::IDNumber 身份证号、Field::Radio 单选、Field::Checkbox 多选、Field::File 附件、Field::Location 定位、Field::Member 人员、Field::Organization 组织、Field::Calculated 计算字段
identity_key字段标识同一归属下唯一,字母数字下划线
title字段名称表单上显示的标题
required是否必填默认否;不传则保持原值
settings字段设置随类型而异(如数值的 min/max、日期的 input_type、计算字段的 formula);不认识的键会被丢弃。不传则保持原设置,传空对象才是清空
options选项单选/多选字段必需,元素为 { "value": "a", "label": "甲" };按 value 对齐,value 建后不可改,删空会返回 422

子流程与子流程节点

子图的存亡完全由子流程节点决定,不由 child_graphs 数组决定,且子图的 key 必须等于子流程节点的 key

操作做法
新建子流程vertices 里声明一个 Vertex::SubProcess 节点即可,系统自动创建同 key 的子图并预置 start / end 两个节点。无需为它补 child_graphs 条目
编辑子流程内部child_graphs 里声明一个 key 等于该节点 key 的对象,内部结构与根图完全一致(vertices / edges / child_graphs,可继续嵌套)
删除子流程vertices 里去掉该节点,整张子图连同内容级联删除
只改深层某张子图只发那一层的 child_graphs 即可,未提及的子图不受影响 —— 这正是子图走增量的用意

请求示例(同一请求内既建子流程节点,又写好它的内部)

{
  "workflow": {
    "graph": {
      "vertices": [
        { "key": "start", "type": "Vertex::Begin", "position": { "x": 200, "y": 80 } },
        { "key": "sub_1", "type": "Vertex::SubProcess", "title": "分支会签", "position": { "x": 200, "y": 200 } },
        { "key": "end", "type": "Vertex::End", "position": { "x": 200, "y": 320 } }
      ],
      "edges": [
        { "key": "e1", "source_key": "start", "target_key": "sub_1" },
        { "key": "e2", "source_key": "sub_1", "target_key": "end" }
      ],
      "child_graphs": [
        {
          "key": "sub_1",
          "vertices": [
            { "key": "start", "type": "Vertex::Begin", "position": { "x": 200, "y": 80 } },
            { "key": "review", "type": "Vertex::Normal", "title": "会签", "position": { "x": 200, "y": 200 },
              "user_boundary": { "assignee_source": "static", "user_ids": [43, 44] } },
            { "key": "end", "type": "Vertex::End", "position": { "x": 200, "y": 320 } }
          ],
          "edges": [ { "key": "s1", "source_key": "start", "target_key": "review" } ]
        }
      ]
    }
  }
}

错误示例

422  { "errors": ["子流程 sub_9 不存在"] }   // child_graphs 里的 key 没有对应的子流程节点

机器节点

机器节点用 automation_agent 配置推送地址与请求头。响应中会回显该节点的 callback_secret 明文 —— 外部系统凭它签名回调,请妥善保管,不要外泄给浏览器端。 Secret 由服务端生成,本接口不接受写入;需要轮换请到管理后台操作。

机器节点的请求与响应片段

// 请求
{ "key": "robot", "type": "Vertex::Machine", "title": "同步到 ERP",
  "automation_agent": { "push_url": "https://erp.example.com/hooks/flowcraft",
                        "push_headers": { "X-Api-Key": "xxxx" } } }

// 响应
{ "key": "robot", "type": "Vertex::Machine", "title": "同步到 ERP",
  "automation_agent": { "push_url": "https://erp.example.com/hooks/flowcraft",
                        "push_headers": { "X-Api-Key": "xxxx" },
                        "has_secret": true,
                        "callback_secret": "cs_9f8e7d6c5b4a" } }

连线与发起限制对象

字段中文名称说明
edges[].key连线标识同一张图内唯一
edges[].source_key起点节点同图内的节点 key
edges[].target_key终点节点同图内的节点 key
edges[].condition流转条件{} 表示无条件;否则为 { "all": [ 条件… ] },条件之间是「且」的关系
condition.all[]单条条件字段条件用 field_identity_key + op + values / min / max;发起人条件用 subject: "proposer" + user_ids / organization_ids
setting.proposal_time_limited限制发起时段开启后仅在规则命中的时段内可发起
setting.proposal_time_rules[]发起时段规则多条之间是「或」:{ "type": "periodic", "days": [1,2], "start_time": "09:00", "end_time": "18:00" }(days 为 1–7,7 是周日)、{ "type": "workday", "start_time": "09:00", "end_time": "18:00" }{ "type": "custom", "starts_at": "2026-08-01 09:00", "ends_at": "2026-08-31 18:00" }。传空数组即清空所有规则
setting.proposal_period_count周期内次数上限配合 proposal_period_unitday 天 / week 周 / month 月 / custom 自定义天数,自定义时用 proposal_period_days 指定天数)
setting.proposal_total_count总次数上限配合 proposal_total_scopemember 每人 / team 全空间)使用

流程记录接口

路径须含流程编号 :workflow_id。「流程记录 · 查询」用于列表与详情,「流程记录 · 发起」用于新建记录。不支持跨流程查询。

GET /api/v1/workflows/:workflow_id/journeys

列出指定流程下的记录,支持多维筛选与排序。需「流程记录 · 查询」权限。

参数中文名称位置必填说明
workflow_id流程编号路径要查询的流程 ID;不存在时 404
proposer发起人Query按发起人姓名模糊匹配
created_from创建时间起Query创建时间下限,如 2026-01-01 或 ISO8601
created_to创建时间止Query创建时间上限;仅日期时含当天 23:59:59
statuses[]流程状态Query可多选:processing(进行中)、refused(已回退)、completed(已完成)
overdue仅逾期Query1true 时仅返回逾期记录
current_nodes[]当前节点Query按当前所在节点过滤;传节点 vertex_key,或 __completed__ / __refused__
filters[field_key][value]表单精确筛选Query按发起人表单字段精确匹配,field_key 为字段标识
filters[field_key][values][]表单多选筛选Query多选字段包含给定选项之一
filters[field_key][from]表单范围下限Query数值或日期字段的下限
filters[field_key][to]表单范围上限Query数值或日期字段的上限
sort排序字段Query默认按创建时间;也可传流程中可排序数值字段的标识
direction排序方向Queryasc 升序 / desc 降序,默认降序
page页码Query分页页码,从 1 开始
per_page每页条数Query每页返回的记录数量

请求示例(发起人 + 状态筛选)

GET /flowcraft/api/v1/workflows/3/journeys?proposer=张&statuses[]=processing&page=1
Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.xxxxx.yyyyy
Accept: application/json

请求示例(按表单字段「请假天数」2~5 天筛选并降序)

GET /flowcraft/api/v1/workflows/3/journeys?filters[days][from]=2&filters[days][to]=5&sort=days&direction=desc
Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.xxxxx.yyyyy
Accept: application/json

响应示例 200(每项为完整 journey 对象,结构与详情接口完全一致,含 assignments / current_assignment / moments / workflow_version;此处仅示意数组外层)

[
  {
    "id": 101,
    "status": "processing",
    "current_assignment_id": 512,
    "graph_path": [],
    "created_at": "2026-07-01T09:30:00.000+08:00",
    "updated_at": "2026-07-01T14:20:00.000+08:00",
    "deadline_at": null,
    "proposer": { "id": 42, "name": "张三" },
    "current_assignment": { "id": 512, "status": "pending", "vertex_key": "approve_2", "graph_path": [], "completed_at": null, "deadline_at": "2026-07-04T18:00:00.000+08:00", "assignee": { "id": 44, "name": "王五", "type": "User" } },
    "assignments": [ "…同详情接口…" ],
    "moments": [ "…同详情接口…" ],
    "workflow_version": { "id": 12, "version_number": 2, "fields_snapshot": [], "graph": {} }
  }
]

GET /api/v1/workflows/:workflow_id/journeys/:id

获取单条流程记录完整详情,直接映射数据模型关联(任务、作答表单、时间线、流程版本与流程图)。记录须属于该流程,否则 404。需「流程记录 · 查询」权限。

参数中文名称位置必填说明
workflow_id流程编号路径流程 ID
id记录编号路径流程记录 ID,须属于上述流程

请求示例

GET /flowcraft/api/v1/workflows/3/journeys/101
Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.xxxxx.yyyyy
Accept: application/json

响应示例 200(张三发起后李四已通过「部门审批」,当前停留在「人事备案」。键名即模型关联名;空关联省略——approve_1 未提交表单,故其 assignment 不含 response 键。moments 为时间线事件,升序)

{
  "id": 101,
  "status": "processing",
  "current_assignment_id": 512,
  "graph_path": [],
  "created_at": "2026-07-01T09:30:00.000+08:00",
  "updated_at": "2026-07-01T14:20:00.000+08:00",
  "deadline_at": null,
  "proposer": { "id": 42, "name": "张三" },
  "current_assignment": { "id": 512, "status": "pending", "vertex_key": "approve_2", "graph_path": [], "completed_at": null, "created_at": "2026-07-01T14:20:00.000+08:00", "updated_at": "2026-07-01T14:20:00.000+08:00", "deadline_at": "2026-07-04T18:00:00.000+08:00", "assignee": { "id": 44, "name": "王五", "type": "User" } },
  "assignments": [
    {
      "id": 510, "status": "proposed", "vertex_key": "begin", "graph_path": [],
      "completed_at": "2026-07-01T09:30:00.000+08:00", "created_at": "2026-07-01T09:30:00.000+08:00", "updated_at": "2026-07-01T09:30:00.000+08:00", "deadline_at": null,
      "assignee": { "id": 42, "name": "张三", "type": "User" },
      "response": {
        "id": 301, "user_id": 42, "created_at": "2026-07-01T09:30:00.000+08:00", "updated_at": "2026-07-01T09:30:00.000+08:00",
        "entries": [
          { "id": 901, "field_identity_key": "reason", "value": "出差参展", "created_at": "2026-07-01T09:30:00.000+08:00", "updated_at": "2026-07-01T09:30:00.000+08:00" },
          { "id": 902, "field_identity_key": "days", "value": 3, "created_at": "2026-07-01T09:30:00.000+08:00", "updated_at": "2026-07-01T09:30:00.000+08:00" }
        ]
      }
    },
    { "id": 511, "status": "approved", "vertex_key": "approve_1", "graph_path": [], "completed_at": "2026-07-01T14:20:00.000+08:00", "created_at": "2026-07-01T09:30:00.000+08:00", "updated_at": "2026-07-01T14:20:00.000+08:00", "deadline_at": null, "assignee": { "id": 43, "name": "李四", "type": "User" } },
    { "id": 512, "status": "pending", "vertex_key": "approve_2", "graph_path": [], "completed_at": null, "created_at": "2026-07-01T14:20:00.000+08:00", "updated_at": "2026-07-01T14:20:00.000+08:00", "deadline_at": "2026-07-04T18:00:00.000+08:00", "assignee": { "id": 44, "name": "王五", "type": "User" } }
  ],
  "workflow_version": {
    "id": 12,
    "version_number": 2,
    "fields_snapshot": [
      { "type": "Field::Text", "title": "请假事由", "identity_key": "reason", "options": [], "required": true, "position": 1, "settings": {} },
      { "type": "Field::Integer", "title": "请假天数", "identity_key": "days", "options": [], "required": true, "position": 2, "settings": {} }
    ],
    "graph": {
      "id": 7,
      "vertices": [
        {
          "id": 21, "key": "begin", "type": "Vertex::Begin", "title": "发起",
          "position": { "x": 80, "y": 200 },
          "user_boundary": { "id": 31, "user_count": 0, "users_preview": [], "organization_count": 0, "organizations": [], "assignee_source": "static", "assignee_source_vertex_key": null },
          "parallel_enabled": false, "assignee_selection_enabled": false, "deadline_enabled": true, "delay_request_enabled": false
        },
        {
          "id": 22, "key": "approve_1", "type": "Vertex::Normal", "title": "部门审批",
          "position": { "x": 320, "y": 200 },
          "user_boundary": { "id": 32, "user_count": 1, "users_preview": [{ "id": 43, "name": "李四" }], "organization_count": 0, "organizations": [], "assignee_source": "static", "assignee_source_vertex_key": null },
          "approval_strategy": "any", "approval_threshold": 1, "transfer_enabled": true, "comment_required": false,
          "assignee_source": "static", "assignee_source_vertex_key": null,
          "parallel_enabled": false, "assignee_selection_enabled": false, "deadline_enabled": true, "delay_request_enabled": false,
          "required_branch_count": 1
        },
        {
          "id": 23, "key": "approve_2", "type": "Vertex::Normal", "title": "人事备案",
          "position": { "x": 560, "y": 200 },
          "user_boundary": { "id": 33, "user_count": 1, "users_preview": [{ "id": 44, "name": "王五" }], "organization_count": 0, "organizations": [], "assignee_source": "static", "assignee_source_vertex_key": null },
          "approval_strategy": "any", "approval_threshold": 1, "transfer_enabled": false, "comment_required": false,
          "assignee_source": "static", "assignee_source_vertex_key": null,
          "parallel_enabled": false, "assignee_selection_enabled": false, "deadline_enabled": true, "delay_request_enabled": false,
          "required_branch_count": 1
        },
        { "id": 24, "key": "end", "type": "Vertex::End", "title": "结束", "position": { "x": 800, "y": 200 }, "required_branch_count": 1 }
      ],
      "edges": [
        { "id": 41, "key": "edge_1", "source_key": "begin", "target_key": "approve_1", "condition": {} },
        { "id": 42, "key": "edge_2", "source_key": "approve_1", "target_key": "approve_2", "condition": {} },
        { "id": 43, "key": "edge_3", "source_key": "approve_2", "target_key": "end", "condition": {} }
      ]
    }
  },
  "moments": [
    {
      "id": 501,
      "status": "propose",
      "vertex_key": "begin",
      "graph_path": [],
      "comment": null,
      "metadata": { "entry_ids": [901, 902], "next_vertex_keys": [] },
      "assignment_id": 510,
      "response_id": 301,
      "created_at": "2026-07-01T09:30:00.000+08:00",
      "actor": { "id": 42, "name": "张三", "type": "User" }
    },
    {
      "id": 502,
      "status": "approve",
      "vertex_key": "approve_1",
      "graph_path": [],
      "comment": "同意",
      "metadata": { "vertex_title": "部门审批" },
      "assignment_id": 511,
      "response_id": null,
      "created_at": "2026-07-01T14:20:00.000+08:00",
      "actor": { "id": 43, "name": "李四", "type": "User" }
    }
  ]
}

assignment.status 取值:proposed 发起 / pending 待办 / approved 已通过 / skipped 并行取消 / refused 已回退 / transferred 已转交 / cancelled 已取消。assignee / actor 的 type 为 User 或 Automation::Operator。表单作答统一在 assignments[].response.entries 下,entry.value 为字段原始值。moments.status 取值:propose 发起 / approve 通过 / refuse 回退 / repropose 重新发起 / complete 流程结束 / transfer 转交 / enter_subprocess / exit_subprocess / branch_cancelled / request_delay / approve_delay / reject_delay / machine_dispatch。实际响应字段顺序为 …, assignments, moments, workflow_version(JSON 键顺序不构成约定)。

POST /api/v1/workflows/:workflow_id/journeys

在已发布流程上发起新记录。需「流程记录 · 发起」权限;流程未发布时返回 403。

参数/字段中文名称位置必填说明
workflow_id流程编号路径要发起流程的流程 ID
journey.proposer_id发起人编号Body发起人用户 ID,须为已存在用户
journey.form_data发起表单Body发起人填写的表单,键为字段标识,值须符合字段类型;计算字段由服务端按公式求值,请求中提交的对应值会被覆盖
journey.next_vertex_keys下一节点Body开始节点后存在分支或并行时,指定下一节点的 vertex_key 列表
journey.journey_deadline_at整单截止时间Body整单截止时间,ISO8601 格式,须不早于当前时间
journey.next_vertex_assignees下一节点办理人Body为下一节点指定办理人,含 vertex_keygraph_pathassignee_ids
journey.next_vertex_routes下一节点路径Body高级用法:指定下一节点及子图路径,含 vertex_keygraph_path
journey.next_vertex_deadlines下一节点截止时间Body为下一节点设截止时间,含 vertex_keydeadline_atgraph_path

请求示例(基础发起:仅发起人 + 表单)

POST /flowcraft/api/v1/workflows/3/journeys
Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.xxxxx.yyyyy
Content-Type: application/json

{
  "journey": {
    "proposer_id": 42,
    "form_data": {
      "reason": "出差参展",
      "days": 3
    }
  }
}

请求体示例(完整参数:指定下一节点、办理人、节点与整单截止时间)

{
  "journey": {
    "proposer_id": 42,
    "form_data": { "reason": "出差参展", "days": 3 },
    "next_vertex_keys": ["approve_1"],
    "journey_deadline_at": "2026-07-10T18:00:00+08:00",
    "next_vertex_assignees": [
      { "vertex_key": "approve_1", "graph_path": [], "assignee_ids": [43] }
    ],
    "next_vertex_deadlines": [
      { "vertex_key": "approve_1", "graph_path": [], "deadline_at": "2026-07-04T18:00:00+08:00" }
    ]
  }
}

响应示例 201(返回完整详情,结构与详情接口完全一致,含 assignments / current_assignment / moments / workflow_version;以下为关键字段节选)

{
  "id": 102,
  "status": "processing",
  "current_assignment_id": 520,
  "graph_path": [],
  "created_at": "2026-07-03T10:30:00.000+08:00",
  "proposer": { "id": 42, "name": "张三" },
  "current_assignment": { "id": 520, "status": "pending", "vertex_key": "approve_1", "graph_path": [], "completed_at": null, "deadline_at": "2026-07-04T18:00:00.000+08:00", "assignee": { "id": 43, "name": "李四", "type": "User" } },
  "assignments": [
    {
      "id": 519, "status": "proposed", "vertex_key": "begin", "graph_path": [],
      "assignee": { "id": 42, "name": "张三", "type": "User" },
      "response": {
        "id": 305, "user_id": 42,
        "entries": [
          { "id": 910, "field_identity_key": "reason", "value": "出差参展", "created_at": "2026-07-03T10:30:00.000+08:00", "updated_at": "2026-07-03T10:30:00.000+08:00" },
          { "id": 911, "field_identity_key": "days", "value": 3, "created_at": "2026-07-03T10:30:00.000+08:00", "updated_at": "2026-07-03T10:30:00.000+08:00" }
        ]
      }
    },
    { "id": 520, "status": "pending", "vertex_key": "approve_1", "graph_path": [], "assignee": { "id": 43, "name": "李四", "type": "User" } }
  ]
}

错误示例

403  { "errors": ["流程未发布,无法发起"] }
422  { "errors": ["发起人不存在"] }
422  { "errors": ["请假事由 为必填项"] }