Auto-close stale conversations
Idle threads pile up. Customers who never come back leave rows stuck in the open queue, distorting queue length, per-agent open counts, and the inbox list every agent works from. Auto-close is the tenant-owned control that sweeps those rows away: a background job checks every workspace every 10 minutes and closes conversations that have passed a configurable idle window — no customer message for N days. Every auto-closed row is markedclosed_reason: "auto_stale", fires the same conversation.closed webhook a manual close fires, and is logged to the audit trail as conversation.auto_closed_stale — so downstream reporting splits platform-closed volume from agent-closed volume.
The feature ships off. Nothing changes for your conversations until an owner or admin turns it on.
Configure auto-close
Open Inbox → Settings → Auto-close stale conversations (owner or admin). The page controls three things:- Enable auto-close — the master switch. Off by default; off pauses the sweep without losing your other settings.
- Idle window — how many days a conversation can sit without a new message before the sweep closes it. A whole-number slider from 1 to 90 days, default 7. Fractions and out-of-range values are clamped on save.
- Statuses to close — which statuses the sweep is allowed to close: open, pending, or both. At least one must be selected; the save button is disabled otherwise.
What counts as idle
Idle is measured from the conversation’s most recent message timestamp, on either party. Any message — customer, agent, or AI — restarts the window, so an active thread is never swept. A conversation with no messages at all is also never swept: a never-messaged row is treated as bootstrap noise, not staleness. The idle window is a floor, not a precision timer. A conversation that crosses the threshold is closed on the next 10-minute sweep, so the effective close lands between N days and N days plus 10 minutes after the last message.What auto-close never touches
The sweep applies several guardrails in every pass, independent of your configuration:- Resolved, closed, archived, and snoozed threads — terminal and paused statuses are excluded from the sweep regardless of the statuses you select.
- Anything already closed — a double check alongside the status filter, so a row can’t be re-processed.
- Never-messaged threads — as above.
- Threads still inside the idle window — any row whose last message is younger than the configured window.
- Pending reply approvals. A reply awaiting supervisor approval is a message row on the conversation (
pendingstate) and therefore restarts the idle timer — a thread can’t be swept while an approval is outstanding. See Reply approvals. - AI auto-deflection. Auto-deflect’s post of a KB answer counts as a message for idleness. On the negative-sentiment guardrail, the AI answer is posted but the thread is deliberately held open for a human — it stays in
openuntil your configured scope and idle window eventually sweep it. Shorten the window or un-scopeopenonly if the intent is for swept negative-sentiment threads to stop waiting on an agent.
How auto-close fits the conversation lifecycle
Auto-close is a full-status close — not a soft-hide. It does exactly what an agent clicking Close does, with three deliberate differences:closed_reason: "auto_stale"is stamped on the conversation. Agent-driven closes leave the reason null. Every reports surface and the conversation list filter the two.- The
conversation.closedwebhook fires, exactly as it does for a manual close — payload below. A subscribed CRM updates on the sweep, not just on human action. - The audit event differs:
conversation.auto_closed_stalerather thanconversation.closed, so an audit filter separates platform decisions from human ones.
conversation.closed channel, so an agent watching the thread sees it leave their queue in under a second.
Reopening works identically either way: reopen an auto-closed thread and the closed-reason marker stays on the row for reporting, but the conversation is live again.
Webhook payload on an auto-close sweep
reason field is what tells your CRM the sweep did it, not a person. Subscribe under Settings → Webhooks with the conversation.closed event, same as for manual closes.
Reporting auto-closed vs agent-resolved volume
Filter on the closed-reason column; it is the single split point:- Auto-close volume for a period — count conversations closed with
closed_reason = 'auto_stale'in the window. Counted once per close. - Agent-driven close volume for the same period — count conversations closed with a null closed reason.
open instead of closing it, or the idle window is longer than customer patience. Check the trend before changing the window — the settings page is deliberately low-friction, so a trend-based correction is cheap, but changing the number without a diagnosis tends to just move the same misclassification.
Troubleshooting
Related: Reply approvals · Webhooks — conversation.closed · Inbox SLA timers