Declined Tasks and the Stage Funnel
How a rejected approval becomes a terminal "declined" task outcome, how a flow whose remaining work is all declined closes as declined, and how to read the per-stage funnel of a template from the dashboard, the API, or a scheduled workflow
The declined outcome
A task that is refused at an approval ends with the outcome declined. That covers two cases:
- an approval action on the task is decided as rejected (its status becomes
failed); - a gated stage transition for the task is rejected.
declined is a terminal outcome, like completed. A declined task:
- shows as declined in the list view, the task sheet, and the wizard rail;
- no longer counts as open work. It leaves Needs me, the worklist, reminder and overdue notifications, and the SLA escalation sweep;
- is never flagged as overdue.
The outcome is computed when the task is read, from the flow's activity log. Nothing new is stored, so flows that already ran report their declines correctly without a migration. The task's stored status is unchanged (typically active). API consumers should read the new outcome field instead.
outcome | Meaning |
|---|---|
open | Still being worked, or waiting on a decision |
completed | Finished |
declined | Refused at an approval, and nothing has reopened it since |
withdrawn | Archived without being finished |
What clears a decline
A decline stays in place until something happens to the task after it.
A rejected approval action is cleared when:
- the task is moved to another stage;
- the approval is resubmitted, or decided again with a status other than rejected;
- the stage is reopened.
A refused transition is cleared by any of those, and also when the task is submitted for approval again, when the transition is approved, or when the task is completed.
A decline does not advance the flow. A stage whose tasks were declined is not treated as drained, so downstream stages stay locked. To continue, reopen the stage or move the task.
outcome appears on:
GET /api/process-flows/{id}(each entry intasks)GET /api/process-flows/{id}/tasks/{taskId}
A flow that ends declined
When a decline is all the work a flow has left, the flow closes on its own with the outcome declined. Nobody has to cancel it or press Finish.
A flow closes as declined when:
- at least one of its tasks is declined;
- no other task can still be worked: none is active or waiting for a transition approval;
- no locked task is waiting on a scheduled unlock time.
Tasks that are locked behind the decline do not keep the flow open. That covers a task in a later stage that the decline stops from starting, and a task that depends on the declined one. The flow ends where the decline stopped it.
A flow that still has other work stays open until that work finishes. The moment the last of it finishes, the flow closes as declined. Finish does the same: it skips the remaining optional actions and then closes the flow as declined. A declined task never blocks Finish.
The closed flow's stored status is completed, the same value a flow that ran to the end has. The flow's outcome tells the two apart:
Flow outcome | Meaning |
|---|---|
open | Not started, in progress, or on hold |
completed | Every stage finished |
declined | Closed because its remaining work was declined |
cancelled | Cancelled |
The dashboard card and the header of the flow's own page read Declined, and the closing card in the walkthrough says the flow closed as declined. The flow appears under the Completed tab, because that tab lists every closed flow.
The outcome is returned by:
GET /api/process-flows(each flow'soutcome; add?limit=N, 1–500, for only the newest N flows)GET /api/process-flows/{id}(data.outcome)POST /api/process-flows/{id}/finish(data.outcome)- the stage funnel (
flows, see below)
Taking a decline back after the flow closed
A flow that closed as declined can come back. If someone decides the declined approval again, or reopens a stage, the flow returns to in_progress and the work it unlocks continues. If that decision was the last thing the flow needed, it records a normal completed outcome instead.
The flow closes, or comes back, as part of the decision. If that step fails, the decision itself still stands, and an hourly maintenance pass closes or reopens the flow later. In that case a flow can stay in_progress for up to about 70 minutes after its last task was declined.
The stage funnel
The funnel shows how instances of one template move through its stages over a time window.
Its stage counts are task visits, not instances. A visit is one task's stay in one stage, from the moment the task can be worked there until it leaves. An instance whose three tasks pass through a stage adds three visits to that stage, and a task sent back to a stage it already left starts a new visit there. The flows field, described below, counts whole instances.
For each stage the funnel reports:
| Field | Meaning |
|---|---|
entered | Visits that arrived in the stage during the window |
advanced | Visits that moved forward to a later stage |
declined | Visits that ended declined in this stage |
returned | Visits sent back to an earlier stage |
withdrawn | Visits whose task was archived |
open | Visits that are still in the stage |
conversionRate | advanced / (entered − open), or null until a visit is decided |
dwell | Median and p90 time in the stage, for visits that left it |
timeToFirstAction | Gate stages only: median and p90 time from arrival to the first action anyone took |
Stages are identified by their slug (key), so the same stage lines up across template versions.
In the dashboard
Open Process Flows and choose the Funnel tab. Pick a template to see the last 90 days. Days are UTC calendar days for every viewer, whatever their own time zone, and the panel shows the covered dates with a "UTC" label. Above the table, a line says how the counted flows ended, including how many closed as declined. Each row shows where the stage's visits went: advanced, declined, returned, withdrawn, or still open. Those five add up to Entered, and conversion is computed from the first four.
Over the API
curl "https://<host>/api/process-flows/stage-funnel?environmentId=$ENV_ID&templateId=$TEMPLATE_ID" \
-H "x-api-key: $SCRYDON_API_KEY"| Parameter | Required | Notes |
|---|---|---|
environmentId | Yes | The workspace environment |
templateId | Yes | The instance's templateId, for example <extensionId>:<flow-slug> |
from, to | No | ISO 8601 timestamps with an offset, used as exact instants. The default is the last 90 UTC calendar days: from 00:00 UTC 89 days before today (UTC) up to now. When you pass only to, the default from counts back from the UTC day of to. A window can be at most 366 days, and from must be before to |
The response is { "data": { templateId, window, instanceCount, truncated, flows, stages } }. flows counts the counted instances by flow outcome: { open, completed, declined, cancelled }. It sums to instanceCount. One request counts at most the 500 newest instances. When there are more, truncated is true.
The caller needs read access to process flows in the environment. An API key works: it is bound to its own workspace, and it must belong to a user. Callers with no user behind them are refused with 401.
Recipe: alert on a stage that stalls
No dedicated block is needed. The funnel is a normal API, so a scheduled workflow can watch it:
- Add a Schedule trigger, for example every Monday at 08:00.
- Add an API block that calls
GET /api/process-flows/stage-funnelwith anx-api-keyheader. Store the key as a secret. - Add a Condition block on the stage you care about.
stagesis in stage order, sostages.0is the first stage. For example:Reference the one number you compare, not the whole response. A Condition block pastes each reference into the expression as text, and an expression can be at most 2,000 characters long.javascript<api.data.data.stages.0.conversionRate> !== null && <api.data.data.stages.0.conversionRate> < 0.3<api.data>would paste the entire funnel, every stage included, so the condition fails on any template with three or more stages. - On the true branch, send the notification with whatever messaging block you already use (email, Slack, Teams).