Skip to main content
pcollins.tech
Back to all posts
Why your WhatsApp test number never receives a message
4 min read
Engineering

Why your WhatsApp test number never receives a message

#post-mortem#whatsapp#debugging#personal-ops-system

Share this post

The webhook was green. The messages field was subscribed. Meta's dashboard was happy. I sent a message to the number and waited for my assistant to reply.

Nothing arrived. Nothing kept arriving. This is the story of the afternoon I lost to a number that, by design, cannot be spoken to.

I'd been wiring a parked WhatsApp intake scaffold for my personal assistant: environment variables, signed-webhook verification, a seeded channel binding, the full inbound-to-reply loop. Three separate traps sat between me and a working thread. Only one of them was the real villain.

Trap one: the migration that was never applied

The first failure was honest and quick. Seeding the channel binding failed on a check constraint. The reason was that the migration defining it had never reached the hosted database. Weeks earlier, a previous incident had prevented some migrations from being applied; this one was among them, still sitting in the repo, never run.

Fine. Apply it over psql. But that surfaced the second trap.

Trap two: the guardrail that saved the wrong database

The tempting way to apply a migration here is the Supabase MCP integration: it's right there, it can run SQL. I didn't, because it's pointed at a different project.

I checked rather than assumed. The MCP's project resolved to a different application from another project. The one I actually wanted was for the project I was working on. Same account, different database. Running the migration through the MCP would have altered the wrong project's schema, cleanly and confidently, and I'd have spent the next hour wondering why nothing changed in the app.

Guardrail: Verify the target before you run the write. It is dull to follow and very cheap compared to the alternative.

Applying over psql had its own small comedy. I had to probe several connection-pooler regions to find the project's home, spotting it as the one region that returned an authentication error rather than a connection error: an auth failure means the server recognised the project reference, a connection failure means it didn't. And the database password in my local env file was stale, the old local-stack one; the real hosted password was a different, longer string. All annoying, all solvable.

Trap three: the number that cannot receive a message

With the binding seeded and the loop live, everything looked right and still nothing arrived. This was the one that could have eaten a whole day, because there was no error anywhere to chase. Green webhook, subscribed field, silence.

Here's the thing nobody puts in front of you: a Meta WhatsApp test number cannot receive a cold inbound message. It is outbound-only, and only to recipients you've explicitly verified. You cannot start a conversation to it. So a customer messaging your test number does not fail loudly; it simply never happens.

I'd built a perfectly good machine for answering messages that, on that number, could never arrive. The fix was to link a real business number instead, which moves you into WhatsApp's "Coexistence" territory and is its own adventure. But the moment I did, the loop lit up.

What I took away

Two things.

The obvious one: when a system is green everywhere and does nothing, stop looking for a bug and start questioning the assumption underneath. Mine was "a number you can send to is a number you can receive on." For Meta test numbers, that's false, and nothing in the happy path tells you so.

The quieter one: the most valuable step that afternoon was the boring check that the MCP was pointed at the wrong database. No error would have caught that. The habit did.

More war stories as they happen, as I build this in the open.

Found this helpful? Share it!

Enjoyed this post? Subscribe to my newsletter for more insights on web development, career growth, and tech innovations.

Subscribe to Newsletter