Ask before acting
When an agent wants to do something that needs approval, Zupflow pauses the run. Your product asks the person; your backend sends their decision. The Console only observes.
sequenceDiagram actor P as Person participant App as Your product participant B as Your backend participant Z as Zupflow Z->>Z: a call needs approval, run pauses Z-->>B: webhook run.waiting_for_approval B->>Z: read run events B->>App: show the pending call App->>P: Allow "create_task"? P->>App: Allow App->>B: decision B->>Z: resolve approval (API key) Z->>Z: decided again, call sent, run continuesWhat the person sees
Section titled “What the person sees”- Issue
- ENG-212 · Billing export times out
- Change
- Cycle:
This sprint→ Next sprint
approval.requestedeventcall_idto answer withapp_name,toolandargumentsto showresolveApprovalwithapprovedordenied
-
Mark tools as needing approval.
Either the organization’s tool policy sets a tool’s level to
approve, or a grant lists it inapproval_required:await zupflow.grants.create(workspaceId, agentId, {installation_id: installationId,tools: ["list_tasks", "create_task", "delete_task"],approval_required: ["create_task", "delete_task"],}); -
Hear that a run is waiting.
Subscribe an endpoint to
run.waiting_for_approval. The event names the workspace (with yourexternal_id) and the run. -
Find what it wants to do.
Read the run’s events and take the latest
approval.requestedthat has noapproval.resolvedyet:const events = await zupflow.runs.events(workspaceId, runId);const resolved = new Set(events.filter((e) => e.type === "approval.resolved").map((e) => e.data.call_id));const pending = events.filter((e) => e.type === "approval.requested" && !resolved.has(e.data.call_id));// each has data.call_id, the tool and data.argumentsShow the person the tool and its arguments in your own words.
-
Send the decision.
await zupflow.runs.resolveApproval(workspaceId, runId, {call_id: callId,decision: "approved", // or "denied"});An approved call is decided once more just before it’s sent; if something changed meanwhile, it may still be refused. A
reasonwith a denial (up to 500 characters) goes back to the model as the call’s result.
Things to know
Section titled “Things to know”- Decisions need an API key of the run’s environment. A Console session gets
403 approval_requires_api_key. - A run waits as long as it takes. Deleting or disconnecting the installation refuses its waiting calls, and the run continues.
- A decision for a call that no longer waits answers
409 not_waiting. Treat it as already handled.