🧰 Tooling Guide

OpenClaw Channels CLI Guide: status vs --probe, Dead Letters, and Recovering One Account Without a Restart

•7 min read

When a Telegram bot goes quiet, most people restart the Gateway. That is the biggest hammer in the box, and usually the wrong one.

The pages that rank for openclaw channels are the official CLI reference (about 3,400 words), a couple of mirrors that copy it heading for heading, and a hosting provider's support article of around 1,800 words that works mostly through the dashboard. Between them they cover list, status, add, login and logout, and logs. They are accurate. None of them tells you what order to reach for things when one channel account stops answering, and the CLI has a surprisingly fine-grained set of tools for exactly that, ranging from a read that touches nothing to a logout that throws away a WhatsApp pairing and sends you back to your phone for a new QR scan. The commands come first. The recovery order is at the end.

list is an inventory

openclaw channels list shows configured chat accounts with installed, configured, and enabled tags. Add --all to see bundled channels with no account yet and catalog channels that are not on disk. With --json it builds the answer from plugin metadata alone, without contacting the Gateway or running channel code. That makes it safe on a broken box. It also means it can tell you nothing about whether a channel is connected.

A disabled plugin still reports installed: true. Disabling is not uninstalling. And on a multi-agent install with no System Agent set, list returns the shared inventory plus a diagnostic instead of guessing which agent's workspace you meant (the agents CLI guide explains why you want agents.defaults.systemAgent.agentId set anyway).

status reads, --probe tests

Plain channels status reports what the Gateway has recorded about each channel's lifecycle and health, plus secret-free account metadata. It does not resolve credentials or run live hooks. Stale connections stay visible.

channels status --probe is the live path. On a reachable Gateway it runs each account's probe and optional audit, concurrently, with a deadline per channel; a channel that times out returns its recorded state with a warning so one hung provider cannot hold the others hostage. The default timeout is 60000 ms. There is no --deep flag here, and typing it is a common slip, because the top-level openclaw status --deep exists and does something broader.

Two outputs get misread more than the rest:

Config-only summaries

The Gateway was unreachable, so you are looking at what config says, with no live results. A SecretRef credential that this command path cannot read shows as configured with degraded notes.

lifecycle: "blocked"

The channel's plugin failed to load or register. Run openclaw doctor, fix or update the plugin, restart, and check again. The Gateway doctor guide walks through the repair side.

A real Gateway error, an unknown --channel for example, exits nonzero rather than falling back. That makes channels status --probe --json usable in a scheduled check, as long as your script handles the boot case: if the Gateway is still starting when the readiness budget runs out, the command exits cleanly and --json returns { "status": "starting" } with the startup phase. Treat that as a retry.

Sessions are a terrible health signal

openclaw sessions lists stored conversation rows. After a Discord provider restart, a connected and perfectly healthy account can show no session row at all until somebody talks to it.

Dead letters: list and resubmit failed inbound events

Inbound events that use up their retry policy are kept in the shared state database for the queue's failed-entry retention period. This is the feature I wish more people knew about, because "the bot ignored me yesterday afternoon" is often sitting right there with a reason attached.

openclaw channels dead-letters list --channel telegram --account default
openclaw channels dead-letters list --channel telegram --account default --json

Text output gives event ids, failure reasons, attempt counts, and ages. JSON adds the retained payload, metadata, lane, and attempt timestamps. openclaw health reports dead-letter counts and the oldest failure age per account, so that is the number worth alerting on.

Fix the cause first. Then:

openclaw channels dead-letters resubmit <event-id> --channel telegram --account default

Resubmission keeps the payload and lane, resets the attempt counter and queue age, and swaps the failed marker atomically, which means running it twice while the event is pending refuses instead of dispatching the message a second time. Completed events cannot be resubmitted. Rows from before payload retention existed will list but refuse to resubmit. Run all of this on the Gateway host, because it reads the same database the channel runtime writes.

The blank --account guard

Omitting --account means the default account. Passing an empty value is an error. The rule holds across add, login, logout, remove, capabilities, resolve, and both dead-letter commands, and it exists for one reason: --account "$ACCT" with ACCT unset would otherwise log out or delete an account nobody named. channels logs --lines "" is rejected the same way.

add, remove, and the routing they leave alone

openclaw channels add --channel telegram --use-env
openclaw channels add telegram --help
openclaw channels remove --channel telegram --delete

--use-env checks the variables the channel plugin declares (for Telegram, TELEGRAM_BOT_TOKEN) before writing config, and the Gateway service needs the same environment as your shell. Flags belong to the channel, so channels add telegram --help shows Telegram's options and bare channels add --help shows almost nothing useful. New credentials go into the shared secret store with a store SecretRef in openclaw.json; the secrets guide covers how that store behaves.

Non-interactive add never creates routing bindings. If you script a second Telegram account and wonder why messages to it land nowhere, that is why, and a bare channel binding with no account id only matches default. Without --delete, remove disables the account and keeps its config. With it, config goes and there is no prompt.

Recovery order, cheapest first

This is the order I use when one account stops responding. Each step costs more than the one before. Stop as soon as you have an answer.

# 1. What does the Gateway already know?
openclaw channels status --channel whatsapp

# 2. Is the account actually reachable right now?
openclaw channels status --channel whatsapp --probe

# 3. What did it say while failing?
openclaw channels logs --channel whatsapp --lines 400

# 4. Did inbound messages pile up?
openclaw channels dead-letters list --channel whatsapp --account <id>

# 5. Bounce one account, keep its pairing
openclaw gateway call channels.stop  --params '{"channel":"whatsapp","accountId":"<id>"}'
openclaw gateway call channels.start --params '{"channel":"whatsapp","accountId":"<id>"}'

Step five is the one the ranking pages bury. The channels.stop and channels.start RPCs need operator.admin, restart a single account, and leave credentials and pairing in place. Read the outcome on start carefully. A retry with stop-in-flight means wait. A skipped with secret-unavailable or unlinked means no amount of restarting will help. And started: true only says the runtime is running; it says nothing about whether the provider connection is healthy, so go back to step two afterwards.

Below that sit the expensive options. openclaw gateway restart drops every channel to fix one. openclaw channels logout clears the account's credentials, stops the live listener when the Gateway is reachable, and sends you back to channels login from a terminal on the Gateway host, since agent exec blocks that interactive flow. For WhatsApp that means a fresh QR scan. Logout also does not revoke provider-side tokens; it only reports whether the plugin cleared saved auth.

One thing that confused me early. If the box slept, the Gateway may already be retrying: host-thaw recovery kicks in after a gap of at least 45 seconds past the normal cadence, and its channel restart retries expire ten minutes after detection. Give it those ten minutes before you start escalating.

Final verdict

Alert on dead-letter counts from openclaw health, put channels status --probe --json in cron, and learn the channels.stop/channels.start pair before you need it. For the Slack and Discord setup that comes before any of this, the chat integration guide starts from zero. Restart the whole Gateway last.

⚡

Ready to build?

Get the OpenClaw Starter Kit — config templates, 5 production-ready skills, deployment checklist. Go from zero to running in under an hour.

$14 $6.99

Get the Starter Kit →

Also in the OpenClaw store

🗂️
Executive Assistant Config
Buy
Calendar, email, daily briefings on autopilot.
$6.99
🔍
Business Research Pack
Buy
Competitor tracking and market intelligence.
$5.99
⚡
Content Factory Workflow
Buy
Turn 1 post into 30 pieces of content.
$6.99
📬
Sales Outreach Skills
Buy
Automated lead research and personalized outreach.
$5.99

Get the free OpenClaw quickstart guide

Step-by-step setup. Plain English. No jargon.