approval_expired (410)
What you’ll see
When the agent polls GET /v1/approvals/:id:
{
"approval_id": "01HKZ7...",
"status": "expired",
"result": null,
"execution_error": null,
"expires_at": "2026-05-18T10:40:55Z",
"executed_at": null,
"created_at": "2026-05-17T10:40:55Z"
}Or, when a delegate or owner clicks an old approval magic link:
{ "error": "approval_expired", "correlation_id": "..." }with HTTP status 410.
Why
Every pending approval has a hard 24-hour expiry. If the owner doesn’t
decide within that window, the approval row is moved to status = 'expired' by the proxy’s expiry sweep, and the agent’s poll sees
expired from that point forward.
The 24-hour window is deliberate: it’s long enough for an owner to sleep, attend meetings, travel, etc., but short enough that a queued action doesn’t sit indefinitely. The window is not configurable today.
Fix
Approvals are not retryable in place. Either:
-
The agent re-issues the request. This creates a fresh approval with a new 24-hour window. The agent should explain to the user why it’s asking again (“The previous approval expired. Re-requesting to send the email — please approve.”).
-
You enable push notifications. Most expiries are because the owner missed the notification. Settings → Push Notifications, then enrol a passkey on your phone so the approval lands one-tap. See Push notifications setup.
-
You add approval delegates. If the primary owner is unavailable, delegates configured in Settings → Approval Delegates receive magic- link emails for every approval. Any delegate can decide. See Delegate approvals.
Why not auto-retry?
Approval expiry is a real signal — the human review window passed without a decision. Auto-retrying would undermine the human-in-the-loop guarantee that’s the whole point of an approval queue. The agent should treat expiry as a “I should re-evaluate whether this is still the right action” moment, not as transient failure.