8.8 KiB
Approval Events
Prerequisite: Read
../SKILL.mdfirst for theevent consumeessentials (commands, subprocess contract, jq usage).
Key catalog (2)
| EventKey | Purpose |
|---|---|
approval.instance.status_changed_v4 |
An approval instance status changed |
approval.task.status_changed_v4 |
An approval task status changed |
Both keys use a Custom schema. The raw Lark schema 2.0 envelope is flattened: event metadata is exposed as type, event_id, and timestamp, while approval business fields are exposed at the top level.
Both keys carry a PreConsume hook that subscribes the current authorized user through the Approval subscription APIs before listening. The consumer intentionally does not unsubscribe on exit; the server-side Approval subscription relation remains until it is canceled outside event consume. These keys require --as user.
Listener and subscription selection
At the raw CLI level, each event consume process accepts exactly one EventKey. approval.instance.status_changed_v4 and approval.task.status_changed_v4 have different output shapes, so listening to both still means two processes.
For Approval only, subscription_type is an optional setup param used by PreConsume to register server-side Approval subscription relations before the local listener starts. It is not an output field, a local event filter, or a local subscription identity. The pushed event does not say which subscription relation caused delivery, and one business event can match both relations; deduplicate with event_id when needed.
subscription_type may be omitted, a single value, a comma-separated list, or a JSON string array:
# Omitted: register both INVOLVED_APPROVAL and MANAGED_APPROVAL for this EventKey
lark-cli event consume approval.instance.status_changed_v4 --as user
# Single relation
lark-cli event consume approval.instance.status_changed_v4 \
-p subscription_type=INVOLVED_APPROVAL \
--as user
# Explicit multi-relation registration for one local consumer
lark-cli event consume approval.task.status_changed_v4 \
-p subscription_type=INVOLVED_APPROVAL,MANAGED_APPROVAL \
--as user
# JSON array form; quote it for the shell
lark-cli event consume approval.task.status_changed_v4 \
-p 'subscription_type=["INVOLVED_APPROVAL","MANAGED_APPROVAL"]' \
--as user
| Value | Meaning |
|---|---|
INVOLVED_APPROVAL |
Receive events where the current user is the approval requester or approver |
MANAGED_APPROVAL |
Receive events under approval definitions managed by the current user |
User-intent inference:
| User intent | EventKey(s) | subscription_type |
|---|---|---|
| Mentions approval instances, approval forms, approval order/status, or "instance status" | approval.instance.status_changed_v4 |
infer from relation words below |
| Mentions approval tasks, approval todo items, approver operations, or "task status" | approval.task.status_changed_v4 |
infer from relation words below |
| Says "approval status changes/events" without saying task vs instance | both EventKeys | infer from relation words below |
| Says "my approvals", "approvals involving me", "I requested/approved", "待我审批", "我发起/我参与" | requested EventKey(s) | INVOLVED_APPROVAL |
| Says "approvals I manage", "managed definitions", "definitions managed by me", "我管理的审批定义" | requested EventKey(s) | MANAGED_APPROVAL |
| Explicitly asks for both involved and managed, or says "all approval subscriptions" | requested EventKey(s), or both if EventKey is also ambiguous | omit subscription_type, or pass both values in one -p |
| Relation is ambiguous and the user wants broad coverage | requested EventKey(s), or both if EventKey is also ambiguous | omit subscription_type so PreConsume registers both |
If the user's wording omits the relation and broad listening is acceptable, omit subscription_type. Ask only when registering both relations would be materially harmful.
Scopes & auth
| EventKey | Scope | Auth |
|---|---|---|
approval.instance.status_changed_v4 |
approval:instance:read |
user |
approval.task.status_changed_v4 |
approval:task:read |
user |
Subscription behavior
Startup calls the endpoint for the selected EventKey:
POST /open-apis/approval/v4/instances/subscription
POST /open-apis/approval/v4/tasks/subscription
For each resolved subscription_type, PreConsume sends one request body:
{"subscription_type":"INVOLVED_APPROVAL"}
If subscription_type is omitted, PreConsume sends two registration requests for that EventKey: one with INVOLVED_APPROVAL, then one with MANAGED_APPROVAL. If listening to both instance and task events, run two consumers; each consumer may omit subscription_type to register both relations for its own EventKey.
Do not start two consumers for the same Approval EventKey merely to split INVOLVED_APPROVAL and MANAGED_APPROVAL. The server push and flattened output are keyed by EventKey and cannot be distinguished by subscription relation.
Shutdown behavior:
event consume does not call the Approval unsubscribe APIs when it exits. This applies to graceful exit, Ctrl+C / SIGTERM, stdin EOF, --timeout, and --max-events.
To stop future delivery for a user, cancel the Approval subscription relation outside this consumer. The unsubscribe APIs are separate operations and are not called by event consume.
Output fields
Common fields:
| Field | Type | Description |
|---|---|---|
type |
string | Event type |
event_id |
string | Globally unique event ID; use for deduplication |
timestamp |
string (timestamp_ms) | Event delivery time in milliseconds, taken from header.create_time |
Instance event fields:
| Field | Type | Description |
|---|---|---|
approval_code |
string | Approval definition code; not a subscription dimension |
instance_code |
string | Approval instance code |
external_id |
string | Third-party approval instance id, when present |
status |
string enum | PENDING, APPROVED, REJECTED, CANCELED, DELETED, REVERTED, OVERTIME_CLOSE, OVERTIME_RECOVER |
operate_time |
string (timestamp_ms) | Status change time |
start_user |
object | Instance starter user IDs, omitted when unavailable |
start_user.open_id |
string (open_id) | Instance starter open_id, when present |
start_user.union_id |
string (union_id) | Instance starter union_id, when present |
start_user.user_id |
string (user_id) | Instance starter tenant user_id, when present |
Task event fields:
| Field | Type | Description |
|---|---|---|
approval_code |
string | Approval definition code; not a subscription dimension |
instance_code |
string | Approval instance code |
task_id |
string | Approval task id |
external_id |
string | Third-party approval external id, when present |
task_external_id |
string | Third-party task external id, when emitted |
assigned_user |
object | Task assignee or operator user IDs, omitted for automatic flows without an operator |
assigned_user.open_id |
string (open_id) | Task assignee or operator open_id, when present |
assigned_user.union_id |
string (union_id) | Task assignee or operator union_id, when present |
assigned_user.user_id |
string (user_id) | Task assignee or operator tenant user_id, when present |
status |
string enum | REVERTED, PENDING, APPROVED, REJECTED, TRANSFERRED, ROLLBACK, DONE, OVERTIME_CLOSE, OVERTIME_RECOVER |
operate_time |
string (timestamp_ms) | Status change time |
Examples
# Stream approval instance updates broadly; registers both involved and managed relations
lark-cli event consume approval.instance.status_changed_v4 \
--as user
# Stream approval instance updates only for approvals involving the current user
lark-cli event consume approval.instance.status_changed_v4 \
-p subscription_type=INVOLVED_APPROVAL \
--as user
# Stream approval task updates for definitions managed by the current user
lark-cli event consume approval.task.status_changed_v4 \
-p subscription_type=MANAGED_APPROVAL \
--as user
# Broad approval status listening:
# run both EventKeys as separate processes; omit subscription_type so each registers both relations.
lark-cli event consume approval.instance.status_changed_v4 \
--as user > approval-instance.ndjson &
lark-cli event consume approval.task.status_changed_v4 \
--as user > approval-task.ndjson &
wait
# Listen to both involved and managed task subscriptions with one local consumer.
lark-cli event consume approval.task.status_changed_v4 \
-p subscription_type=INVOLVED_APPROVAL,MANAGED_APPROVAL \
--as user > approval-task.ndjson
# Project a compact approval-task record
lark-cli event consume approval.task.status_changed_v4 \
-p subscription_type=INVOLVED_APPROVAL \
--as user \
--jq '{event_id, task_id, status, at: .operate_time}'