Replace the Chatfuel token
npx @chatfuel/wizard auth rewrites one line of one file. The rest of the job is getting that value to wherever the proxy actually reads it.
A Chatfuel token can read and change every bot in the account it belongs to. Not one bot, not the bots your app happens to show — all of them. That is why it never reaches the browser, and it is also why replacing it is a real remedy rather than a gesture: there is one value, in one place, and swapping it moves the whole deployment at once.
Rotation itself is Chatfuel's, not ours. You generate a new token on the token page; the wizard's job is the second half, putting it into the app without your editing a secret by hand.
Generate the replacement
Open panel.chatfuel.com/integration/auth/token as the account owner and generate a token. Copy it and keep the tab open — nothing checks it until the next step.
Do not assume a shape or a lifetime. The token page decides both, and the wizard rejects only what cannot be a token at all: an empty string, or one with whitespace in it. Everything else goes to the API to be judged.
Run the wizard's auth command in the app
cd my-app
npx @chatfuel/wizard authIt identifies the app by the very line it is about to rewrite — a .env that declares
CHATFUEL_TOKEN. Nothing else counts, and a directory without one is refused by name rather than
half-processed. Run it from somewhere else with --dir:
npx @chatfuel/wizard auth --dir ./my-appThen it asks for the token, masked, and checks it against the API before writing anything —
currentUser, one request. A token the API rejects is re-asked rather than ending the run, three
times; a network failure is not, because it would fail the same way again.
Two ways round the prompt. CHATFUEL_TOKEN in the environment is used on the first attempt
instead of asking. And under --yes, or with no terminal attached, there is no prompt at all: the
environment is the only source, and a token that is missing or rejected stops the run with a
sentence. That last part matters more than it looks — the prompt library exits the process on
end-of-input, so a scripted run that fell through to a question nobody could answer would report
success and change nothing.
Know what it rewrote
One file, one line:
- Every line beginning
CHATFUEL_TOKEN=is removed, and the new value is written as the first line of the file. - The file is written and then
chmodped to0600, so it is readable by you and nobody else on the machine. - Everything else in
.envkeeps its value and its order — the Supabase keys, the workspace ids, the admin password, your own additions.
And that is the list. It touches no other file: not index.html, not the modules, not your
Supabase project, not Vercel. The closing line says Token rotated in .env, which is precisely
what happened.
One edge worth knowing if your .env is hand-maintained. The check that decides whether this is a
Chatfuel app accepts a commented or indented CHATFUEL_TOKEN= line; the rewrite removes only
lines that begin with it exactly. So an indented CHATFUEL_TOKEN=<old> survives the rotation
and sits in the file beside the new one.
Get the new value to where the proxy reads it
The proxy resolves the token once, at startup, out of whatever environment its host hands it. So the file is never the thing that matters — the host is.
The Vite plugin builds its environment bag once, when the config resolves: .env first, then
process.env on top. A running dev server is still holding the old token.
npm run devRestart it. That is the whole step.
Prove the deployment is on the new token
The wizard has already proved the token itself — it printed the account it authenticated as before it wrote anything. What is left is proving the deployment picked it up.
Ask the health route. On your own server that is /healthz, answering ok and the gate's mode:
{ "ok": true, "auth": "off" }On Vercel it is /chatfuel/healthz, and the answer carries a problems array as well — 200 when
it is empty, 503 when it is not, with ProxyTokenMissing in it if no token reached the
deployment at all.
Either way that confirms the proxy has a token. It does not confirm it is the new one: the health route makes no Chatfuel call. So open the app and load a screen that reads real data — contacts, the inbox, a flow. Data on screen is the proof.
The two failures read differently, and it is worth knowing which you are looking at. An absent
token is ProxyTokenMissing, a 500 from the proxy before anything reaches Chatfuel, with a message
naming the variable and never its value. A token Chatfuel rejects is an Unauthorized code
inside an otherwise ordinary response, on every operation, and the API client never retries it.
Both are in Errors.
On Vercel, the old token stays live in the deployment until you push the new one, and nothing
tells you. The rotation succeeds, the wizard says Token rotated in .env, and it is telling the
truth about the only file it touched — while the running app keeps using the value in the
project environment. If you rotated because a token leaked, the rotation is not finished until
npm run deploy has run.
Where the token sits relative to everything else is the token boundary; every variable the app reads is on Environment variables.
Schedule Instagram posts
Chatfuel publishes immediately and stores no post, so a schedule is your own database waking up on a timer and calling your deployment back. The migration, the shared secret, the address it knocks on, and the one call that turns it on.
Run it in CI, or without a terminal
--yes answers every question the wizard asks except two, which have to be in the environment — and it refuses two steps outright.