Files

8.8 KiB

Approval Events

Prerequisite: Read ../SKILL.md first for the event consume essentials (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}'