Skip to content

Delegation & escalation

Two ways a pending step moves when the assigned approver is unavailable.

Delegation

An approver can hand a pending step to another user. The delegate can then act in place of the delegator on that step.

app(\Talivio\ApprovalFlows\ApprovalManager::class)
    ->delegate($approval, from: $manager, to: $deputy, comment: 'Out this week');

What happens:

  • A delegated action is recorded (with delegated_to_id), so the audit trail shows the hand-off.
  • The delegate is notified with the same ApprovalRequestedNotification.
  • canAct() now returns true for the delegate on the current step, alongside the step's normal approvers.

Delegation can be disabled per step:

$flow->steps()->create([
    // ...
    'allow_delegation' => false,
]);

Delegating a step where allow_delegation is false throws ApprovalException::delegationNotAllowed().

Delegation is scoped to the current step. It does not carry forward to later steps, and it does not remove the original approvers — it adds the delegate.

Escalation

Escalation flags an approval that has sat on the same step too long and re-notifies its approvers. It is driven by a scheduled command, so you decide the cadence.

Configuration

// config/approval-flows.php
'escalation' => [
    'enabled' => true,
    'default_after_hours' => 48,
],

Each step may override the window with escalate_after_hours. ApprovalStep::escalationHours() returns the per-step value, or the config default, or null when escalation is disabled.

Scheduling the check

Add the bundled command to your scheduler. It escalates each qualifying approval once per step (it won't re-escalate the same step every run):

// routes/console.php  (Laravel 11/12)
use Illuminate\Support\Facades\Schedule;

Schedule::command('approval-flows:check-escalations')->hourly();

When a step crosses its window, the command:

  • records an escalated action,
  • fires the ApprovalEscalated event (with the approval and the step),
  • re-notifies the current approvers via ApprovalEscalatedNotification.

Reacting to escalations

use Talivio\ApprovalFlows\Events\ApprovalEscalated;

Event::listen(ApprovalEscalated::class, function (ApprovalEscalated $e) {
    // e.g. ping a manager in Slack, raise a ticket, bump a priority…
    Log::warning('Approval stuck', [
        'approval' => $e->approval->id,
        'step' => $e->step->name,
    ]);
});

Escalation never changes the approval's status — it's a nudge, not a decision. The step still needs a real approve or reject to move on.

Next: Notifications.