Recipe · Vibe-coded apps

Your app's first user is you.

You vibe-coded an app, shipped it, closed the laptop. Now the only dashboard that matters is your phone: the app should text you when something real happens — the first signup, the first sale, the first crash. Each moment is one POST /v1/notify. Text join to get a key, drop a snippet in, ship.

§ 1

First signup

The oldest founder ritual, automated: a stranger trusts your thing with their email, your phone buzzes. One fetch at the end of the signup handler — Node, Bun, Next.js API route, wherever the handler lives.

signup handler (JS)
await fetch("https://pingwa.dev/v1/notify", {
  method: "POST",
  headers: {"Authorization": `Bearer ${process.env.PINGWA_KEY}`,
            "Content-Type": "application/json"},
  body: JSON.stringify({text: `🎉 New signup: ${user.email}`}),
  signal: AbortSignal.timeout(5000)
}).catch(() => {});  // .catch = never fails the signup; await = survives serverless freeze

Put PINGWA_KEY in your app's env vars, same as your database URL. That's the whole integration.

§ 2

Payment landed

You already have a Stripe webhook endpoint (or you're about to — Stripe insists). Add a few lines to the checkout.session.completed branch and every sale taps you on the shoulder, wherever you are.

stripe_webhook.py
import httpx, os

# inside your Stripe webhook handler, after signature verification
if event["type"] == "checkout.session.completed":
    try:
        httpx.post("https://pingwa.dev/v1/notify",
                   headers={"Authorization": f"Bearer {os.environ['PINGWA_KEY']}",
                            "Idempotency-Key": event["id"]},
                   json={"text": "💸 New Pro subscriber"}, timeout=5)
    except Exception:
        pass  # the ping must never fail the webhook

Stripe retries webhooks that don't 2xx — so a flaky run can deliver the same event twice. That's why the snippet passes the Stripe event id as Idempotency-Key: pingwa dedupes on it for 24 hours, so a retried event never double-pings you.

§ 3

Prod error

No Sentry, no PagerDuty, no on-call rotation — it's just you. A ping from the except block is the poor man's error tracker, and for a one-person app it's honestly enough to know that it broke and roughly where.

anywhere_it_can_break.py
import httpx, os

def notify(text):
    try:
        httpx.post("https://pingwa.dev/v1/notify",
                   headers={"Authorization": f"Bearer {os.environ['PINGWA_KEY']}"},
                   json={"text": text}, timeout=5)
    except Exception:
        pass  # fire-and-forget: the ping must never crash the app

try:
    handle_request()
except Exception as e:
    notify("🔥 prod error: " + str(e)[:200])
    raise

Two habits worth keeping: wrap the ping in its own try/except (an alerting outage should never take your app down with it), and in retried handlers — webhooks especially — reuse the Idempotency-Key trick from § 2 so a storm of retries costs you one message, not thirty.

One recipient: you.

pingwa is not a bulk channel to your app's users — you are the only recipient. It's your app tapping its maker on the shoulder, on the number that joined. Messaging your users on WhatsApp is a different product entirely (a WABA of your own, opt-in consent, approved templates — see how the official stack works). If your app grows into needing that, let's talk — but the recipes on this page are strictly the app texting you.

§ 4

FAQ

How do I get a WhatsApp message when someone signs up to my app?

Snippet § 1: one fetch (or httpx.post) to /v1/notify at the end of your signup handler, with the new user's email in the text. Text join to pingwa to get the API key, set it as PINGWA_KEY in your app's environment, and the next signup buzzes your phone.

Can I get pinged when my app makes a sale?

Yes — hook it into the Stripe webhook you already have (§ 2). On checkout.session.completed, POST the ping. If you want the amount in the message, it's on event["data"]["object"]["amount_total"]. Since Stripe retries webhooks, pass the Stripe event id as Idempotency-Key so a retry never double-pings you.

What about error alerts — won't an error storm spam me?

It will, unless you dedupe. Don't ping per request: derive an Idempotency-Key from the deploy plus the error class (e.g. err-v42-TypeError-checkout) — pingwa holds each key for 24 hours, so a thousand identical failures cost one message and one buzz. New deploy or new error class → new key → new ping. That's usually all the error tracking a one-person app needs.

Can my app message its users through pingwa?

No — honestly, and by design. pingwa delivers to the phone that joined: yours. Messaging your users on WhatsApp requires your own business account, their opt-in, and template approval — a real product with real compliance, not a snippet. pingwa stays the self-notification layer; for user-facing messaging, start at the comparison page.

QR code to join pingwa on WhatsApp

Scan the code and get instant access. It opens WhatsApp with “join” ready to send, and your API key comes straight back.

The free plan's 30 paid messages a month fit this stage of an app suspiciously well: signups, sales and crashes are exactly the events you hope stay rare — and when they stop being rare, that's the good problem. Replies inside your 24h window are free.