Approval Open API
Create approval tasks, query status, and subscribe to callbacks via Muse Open forwarding.
Approval Open API
POST https://muse-open.test.tezign.com/api/muse/approval-api
Request conventions
- Method:
POST Content-Type:application/json- Body must be valid JSON
- Use
serviceto select the capability
Supported service values:
subscriptionQuerysubscriptionChangelistTemplatescreateApprovaltaskStatusQuery
Unified response
{"code": "0","message": "success","result": {},"traceId": "trace_xxx"}
Common error codes:
400: invalid payload401: authentication failed403: permission denied404: resource not found500: internal error
listTemplates
Request:
{"service": "listTemplates"}
result is an array of templates with fields such as:
id, name, description, enabled, usageCount, autoImportEnabled, targetFolder, workflow.
createApproval
Required fields:
templateIdcreatedByassets(at least one item)assets[].urlmust be a publichttp/httpsURL
Request example:
{"service": "createApproval","templateId": "101","createdBy": "10086","assets": [{"name": "demo.mp4","url": "https://cdn.example.com/m/asset_1.mp4"}]}
Success example:
{"code": "0","message": "success","result": {"taskId": "9527"}}
taskStatusQuery
Request:
{"service": "taskStatusQuery","taskId": "9527"}
result.status values:
PENDING | PROCESSING | APPROVED | REJECTED | CANCELED.
Subscription and callbacks
Check subscription:
{"service": "subscriptionQuery"}
Add subscription:
{"service": "subscriptionChange","operation": "ADD","callbackUrl": "https://example.com/webhook/approval"}
Cancel subscription:
{"service": "subscriptionChange","operation": "DELETE"}
Callback payload specification
After subscriptionChange with operation = ADD succeeds, approval state changes are posted to your callbackUrl.
Callback request basics
- Method:
POST Content-Type:application/json
Callback body:
{"eventId": "evt_xxx","eventType": "APPROVAL","eventTime": "1760258885000","payload": {"eventName": "TASK_APPROVED","orgId": "233","taskId": "9527","taskStatus": "APPROVED"}}
Field notes:
eventId: unique event id (use as idempotency key)eventType: alwaysAPPROVALeventTime: millisecond timestamp stringpayload: business payload
Common payload fields
Every callback payload contains at least:
eventNameorgId(system populated)taskIdtaskStatus(PROCESSING/APPROVED/TIMEOUT)
Full event set
NODE_STARTED: when a node starts (first node, normal transition, or resubmit transition)APPROVER_SUBMITTED: when an approver submits a decision (can happen multiple times per node)NODE_COMPLETED: when a node is completed (approved/rejected)NODE_TRANSFERRED: when flow transfers to another processing node (normal/resubmit/timeout transfer)SUBMITTER_RESUBMITTED: when submitter uploads updated assets at resubmit stepTASK_APPROVED: when task reaches final approved statusNODE_TIMEOUT: when node times out (timeout transfer or re-assignment pending)
Field definitions
payload.node
nodeId(string): node idnodeOrder(number): node order (present in some events)nodeRole(string):normal/resubmit_submitter/resubmit_approver(event-specific)nodeStatus(string): common values includepending/processing/approved/rejected/timeout_transferred/re_assignedsignMode(string):and/or(event-specific)approverCount(number): approver count (event-specific)approvers(array): approver results onNODE_COMPLETED, item fields:id,name,statusstartedAt(string): ISO start timecompletedAt(string): ISO completion timetimeoutHours(number): timeout threshold in hours (timeout events)
payload.approver (APPROVER_SUBMITTED)
id(string): approver user idname(string): approver namedecision(approved|rejected)comment(string)submittedAt(string, ISO)
payload.submitter (SUBMITTER_RESUBMITTED)
id(string): submitter user idname(string): submitter namecomment(string): resubmission commentsubmittedAt(string, ISO)
payload.timeout
transferTo(object | null): timeout transfer target- when present:
{ "id": "...", "name": "..." } - otherwise:
null
- when present:
payload.latestAssets (SUBMITTER_RESUBMITTED)
assetId(string)filePathId(string)version(number)oldStorePath(string)newStorePath(string)updatedAt(string, ISO)
payload.transferReason (NODE_TRANSFERRED)
NEXT_NODE: normal transition to next approval nodeRESUBMIT_SUBMITTER: transition to submitter resubmission nodeRESUBMIT_APPROVER: transition to approver re-review node after resubmissionTIMEOUT_TRANSFER: transition after timeout transfer
Callback examples (all events)
TASK_APPROVED:
{"eventId": "evt_2a93f5f5f4d64907a2f3b73cb8f0f201","eventType": "APPROVAL","eventTime": "1760258885000","payload": {"eventName": "TASK_APPROVED","orgId": "233","taskId": "9527","taskStatus": "APPROVED","operator": {"id": "10086","name": "张三"},"finishedAt": "2026-10-12T08:08:05.000Z"}}
NODE_STARTED:
{"eventId": "evt_d3a39140643a4d73afedf0a47c0a601d","eventType": "APPROVAL","eventTime": "1760258700000","payload": {"eventName": "NODE_STARTED","orgId": "233","taskId": "9527","taskStatus": "PROCESSING","node": {"nodeId": "12001","nodeOrder": 1,"nodeRole": "normal","nodeStatus": "processing","signMode": "and","approverCount": 2,"startedAt": "2026-10-12T08:05:00.000Z"}}}
APPROVER_SUBMITTED:
{"eventId": "evt_8bc9f92f83564f10adf8270b598f95d2","eventType": "APPROVAL","eventTime": "1760258820000","payload": {"eventName": "APPROVER_SUBMITTED","orgId": "233","taskId": "9527","taskStatus": "PROCESSING","node": {"nodeId": "12001","nodeOrder": 1,"nodeStatus": "processing","signMode": "and"},"approver": {"id": "10086","name": "张三","decision": "approved","comment": "同意","submittedAt": "2026-10-12T08:07:00.000Z"},"approverCount": 2}}
NODE_COMPLETED:
{"eventId": "evt_652d4d8c09d24477af9fdb21624fd070","eventType": "APPROVAL","eventTime": "1760258855000","payload": {"eventName": "NODE_COMPLETED","orgId": "233","taskId": "9527","taskStatus": "PROCESSING","node": {"nodeId": "12001","nodeOrder": 1,"nodeStatus": "approved","signMode": "and","approvers": [{"id": "10086","name": "张三","status": "approved"},{"id": "10087","name": "李四","status": "approved"}],"completedAt": "2026-10-12T08:07:35.000Z"}}}
NODE_TRANSFERRED (normal transition):
{"eventId": "evt_21881077723e4a17aa4e2e58ee78ce79","eventType": "APPROVAL","eventTime": "1760258856000","payload": {"eventName": "NODE_TRANSFERRED","orgId": "233","taskId": "9527","taskStatus": "PROCESSING","transferReason": "NEXT_NODE","fromNode": {"nodeId": "12001","nodeOrder": 1,"nodeStatus": "approved"},"node": {"nodeId": "12002","nodeOrder": 2,"nodeRole": "normal","nodeStatus": "pending"}}}
NODE_TRANSFERRED (rejected -> resubmit):
{"eventId": "evt_e612f8b5e1de4960bb712d3df18e2617","eventType": "APPROVAL","eventTime": "1760258900000","payload": {"eventName": "NODE_TRANSFERRED","orgId": "233","taskId": "9527","taskStatus": "PROCESSING","transferReason": "RESUBMIT_SUBMITTER","fromNode": {"nodeId": "12001","nodeOrder": 1,"nodeStatus": "rejected"},"node": {"nodeId": "13001","nodeOrder": 2,"nodeRole": "resubmit_submitter","nodeStatus": "pending"}}}
NODE_TRANSFERRED (resubmit -> re-review):
{"eventId": "evt_f0c43dd5ca5d4fca9e4adbe536fbb8f5","eventType": "APPROVAL","eventTime": "1760259005000","payload": {"eventName": "NODE_TRANSFERRED","orgId": "233","taskId": "9527","taskStatus": "PROCESSING","transferReason": "RESUBMIT_APPROVER","fromNode": {"nodeId": "13001","nodeOrder": 2,"nodeStatus": "approved"},"node": {"nodeId": "13002","nodeOrder": 3,"nodeRole": "resubmit_approver","nodeStatus": "pending"}}}
NODE_TIMEOUT (transferred on timeout):
{"eventId": "evt_b0d67fb6f3de42e79a60b8f9df6ad20d","eventType": "APPROVAL","eventTime": "1760260000000","payload": {"eventName": "NODE_TIMEOUT","orgId": "233","taskId": "9527","taskStatus": "TIMEOUT","node": {"nodeId": "12002","nodeStatus": "timeout_transferred","timeoutHours": 24},"timeout": {"transferTo": {"id": "10100","name": "王五"}}}}
NODE_TIMEOUT (not transferred):
{"eventId": "evt_2e4372871f0c4a7eb95a9d7c638de8a0","eventType": "APPROVAL","eventTime": "1760260100000","payload": {"eventName": "NODE_TIMEOUT","orgId": "233","taskId": "9527","taskStatus": "TIMEOUT","node": {"nodeId": "12002","nodeStatus": "re_assigned","timeoutHours": 24},"timeout": {"transferTo": null}}}
SUBMITTER_RESUBMITTED:
{"eventId": "evt_5d017db5b458443697f6c10d5f6370df","eventType": "APPROVAL","eventTime": "1760259000000","payload": {"eventName": "SUBMITTER_RESUBMITTED","orgId": "233","taskId": "9527","taskStatus": "PROCESSING","node": {"nodeId": "12002","nodeOrder": 3,"nodeStatus": "approved","signMode": "and"},"submitter": {"id": "10010","name": "李四","comment": "已更新素材,重新提交","submittedAt": "2026-10-12T08:10:00.000Z"},"latestAssets": [{"assetId": "asset_1","filePathId": "30001","version": 3,"oldStorePath": "assets/old/asset_1_v2.mp4","newStorePath": "assets/new/asset_1_v3.mp4","updatedAt": "2026-10-12T08:10:00.000Z"}],"latestAssetCount": 1}}
NODE_TRANSFERRED (after timeout transfer):
{"eventId": "evt_15f4348dd4f34a4b9d51ec93313f4dff","eventType": "APPROVAL","eventTime": "1760260001000","payload": {"eventName": "NODE_TRANSFERRED","orgId": "233","taskId": "9527","taskStatus": "PROCESSING","transferReason": "TIMEOUT_TRANSFER","node": {"nodeId": "12002","nodeStatus": "timeout_transferred"},"timeout": {"transferTo": {"id": "10100","name": "王五"}}}}
Event sequence (key flows)
Delivery is at-least-once. Use eventId for idempotent processing.
Normal pass (multi-node)
NODE_STARTED(first node)APPROVER_SUBMITTED(may repeat for each approver)NODE_COMPLETED- If next node exists:
NODE_TRANSFERRED->NODE_STARTED - Repeat 2-4 until final node is complete
TASK_APPROVED
Rejected then resubmitted
APPROVER_SUBMITTED(decision = rejected)NODE_COMPLETED(nodeStatus = rejected)NODE_TRANSFERRED(transferReason = RESUBMIT_SUBMITTER)NODE_STARTED(nodeRole = resubmit_submitter)SUBMITTER_RESUBMITTEDNODE_COMPLETED(resubmission node)NODE_TRANSFERRED(transferReason = RESUBMIT_APPROVER)NODE_STARTED(re-review node)- Back to normal approval flow (
APPROVER_SUBMITTED...)
Timeout transfer / no transfer
- Node timeout triggers
NODE_TIMEOUT(taskStatus = TIMEOUT) - If timeout transfer target exists:
NODE_TRANSFERRED(transferReason = TIMEOUT_TRANSFER) and task returns toPROCESSING - If no transfer target: only
NODE_TIMEOUT(commonlynodeStatus = re_assigned) until manual follow-up