Skip to main content

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 marked closed_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.
The organisation is the scope: the configuration is workspace-wide, not per-channel or per-queue. A single ownership boundary means one agent team can’t inherit another team’s silence threshold. Saved changes take effect on the next sweep — at most 10 minutes later.

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.
Two adjacent lifecycle guardrails live outside the sweep itself and interact with it:
  • Pending reply approvals. A reply awaiting supervisor approval is a message row on the conversation (pending state) 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 open until your configured scope and idle window eventually sweep it. Shorten the window or un-scope open only 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:
  1. 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.
  2. The conversation.closed webhook fires, exactly as it does for a manual close — payload below. A subscribed CRM updates on the sweep, not just on human action.
  3. The audit event differs: conversation.auto_closed_stale rather than conversation.closed, so an audit filter separates platform decisions from human ones.
The real-time inbox event also fires on the same 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

The 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.
A large auto-close share usually means one of two things: agents are leaving resolved work in 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