Integration

pingwa + Home Assistant

Your smart home already knows when the doorbell rings, the alarm trips, or the nightly backup fails. Give it a WhatsApp voice with one rest_command — works with plain YAML you already know, or grab the native integration for a one-click install.

§ 1

Add the rest_command

In configuration.yaml, wire an outbound notify to POST /v1/notify. Get an API key by texting join to pingwa on WhatsApp (see home), then store it in secrets.yaml.

configuration.yaml
# configuration.yaml
rest_command:
  pingwa_notify:
    url: "https://pingwa.dev/v1/notify"
    method: POST
    headers:
      Authorization: !secret pingwa_bearer
      Content-Type: application/json
    payload: '{"text": {{ message | tojson }} }'
secrets.yaml
# secrets.yaml
pingwa_bearer: "Bearer pw_your_key_here"
§ 2

Add pingwa_ask for confirmations

The same pattern works for POST /v1/ask, which sends a question and waits for you to tap a button on WhatsApp — handy for anything you want to confirm rather than just be told about. The real request body is {"text": ..., "buttons": [...]} (a plain list of up to 3 short strings; omit buttons for a free-text reply instead).

The server holds the connection open for up to 90 seconds waiting for your reply, then returns 408 — so give the rest_command a matching timeout (HA's default is only 10s and would cut it off). A late reply isn't lost: it's still retrievable from the inbox/reply endpoints below.

configuration.yaml
# configuration.yaml — add pingwa_ask under the SAME rest_command:
# block as pingwa_notify (one rest_command: key holds all commands)
  pingwa_ask:
    url: "https://pingwa.dev/v1/ask"
    method: POST
    timeout: 95
    headers:
      Authorization: !secret pingwa_bearer
      Content-Type: application/json
    payload: '{"text": {{ message | tojson }}, "buttons": ["Yes", "No"]}'
§ 3

Example automations

Three common triggers, all under one automation: key (or drop the list items into automations.yaml if that's how you split your config). The alarm example shows the flagship two-way move: capture the reply with response_variable and branch on which button was tapped. rest_command hands back the HTTP response as {status, content}, so the parsed JSON body lives under .content. Reply buttons get stable ids in order — b0 is the first button ("Yes"), b1 the second ("No") — read at reply.content.reply.button_id.

configuration.yaml
# configuration.yaml
automation:
  # Doorbell pressed — one-way notify
  - alias: "Doorbell -> WhatsApp"
    trigger:
      - platform: state
        entity_id: binary_sensor.front_door_doorbell
        to: "on"
    action:
      - service: rest_command.pingwa_notify
        data:
          message: "Someone's at the front door 🔔"

  # Alarm triggered — ask, then act on the answer
  - alias: "Alarm triggered -> ask on WhatsApp"
    trigger:
      - platform: state
        entity_id: alarm_control_panel.home
        to: "triggered"
    action:
      - service: rest_command.pingwa_ask
        data:
          message: "🚨 Alarm triggered at home. Call the keyholder?"
        response_variable: reply
      # reply.content.reply.button_id is "b0" for "Yes", "b1" for "No"
      # (on a 408 timeout reply.status is 408 — falls to the default branch)
      - choose:
          - conditions: "{{ reply.content.reply.button_id == 'b0' }}"
            sequence:
              - service: script.call_keyholder
        default:
          - service: rest_command.pingwa_notify
            data:
              message: "No 'Yes' tap — not calling the keyholder."

  # Nightly backup failed — one-way notify
  - alias: "Backup failed -> WhatsApp"
    trigger:
      - platform: state
        entity_id: sensor.backup_status
        to: "failed"
    action:
      - service: rest_command.pingwa_notify
        data:
          message: "Nightly backup FAILED — check the logs"
§ 4

Two-way: pingwa pushes replies into HA

Outbound (HA → your phone) is the rest_command above. For inbound (your WhatsApp reply → HA) pingwa can now PUSH each reply straight to a Home Assistant webhook — no polling loop.

  • Register your HA webhook URL once: POST /v1/webhooks {"url": "https://ha.example.com/api/webhook/<id>"}. It returns a secret (whsec_…) shown only once; the URL must be public HTTPS (up to 5 per account).
  • On every inbound message pingwa POSTs a JSON body {event, message_id, body, button_id, reply_to_message_id, wa_message_id, window_open, created_at}button_id is b0/b1/… for a tapped button (null for free text). HA's built-in platform: webhook trigger fires on that POST and your automation acts on it.
  • A voice message adds a media object {kind:"audio", voice:true, mime_type, url} (and body is empty). GET media.url to fetch the audio — no API key needed (the signature authorizes it), but the link is short-lived (~1h), so fetch promptly. Feed the URL to a media_player or download it in your automation.
  • Each request carries an X-Pingwa-Signature: sha256=<hmac> header (HMAC-SHA256 of the raw body with your secret). HA's webhook trigger can't verify that HMAC on its own — treat the raw endpoint as unauthenticated, keep the HA webhook id (the one in the URL) secret, and verify the signature in a template condition — or install the native integration, which registers the webhook and verifies the HMAC for you. Don't skip this on an internet-exposed HA.
  • If a delivery keeps failing, pingwa retries with backoff and auto-deactivates the webhook after repeated exhausted attempts — check GET /v1/webhooks (active, failure_count) and re-create it once HA is reachable again.

Fallback: polling still works if you'd rather HA ask — a rest sensor or a short-interval automation can call GET /v1/inbox?since=<cursor> and react to new messages the same way.

§ 5

Native integration (HACS)

Prefer entities and services over hand-rolled YAML? The pingwa-hass integration wires everything up for you. Install it via HACS as a custom repository (github.com/grzgrzgrz3/pingwa-hass), add your API key, and you get:

  • a notify.pingwa entity for one-way alerts;
  • a pingwa.ask service that sends a question and hands the answer back via response_variable — no timeout tuning, no .content parsing;
  • a signature-verified inbound webhook: it registers the HA webhook, checks the X-Pingwa-Signature HMAC for you, and fires a pingwa_reply event your automations can trigger on.

Requires Home Assistant 2024.12+. The plain rest_command path above stays the zero-install alternative — pick whichever fits your setup.

§ 6

Why the official Cloud API, not a bridge

pingwa sends through the official Meta WhatsApp Cloud API on its own number, so wiring it into your home automation can't get your personal WhatsApp banned. That is a real distinction from two other kinds of tools people wire into Home Assistant today:

§ 7

Sized for alerts, not alert spam

The free plan covers 30 paid-route notifications a month (replies inside your 24h WhatsApp window are free and unlimited). That's not built for streaming every state change in your house — it's built for the handful of things actually worth a phone buzz: someone's at the door, the alarm tripped, the backup failed. Keep high-frequency sensor chatter in HA's own logbook/notifications, and reserve pingwa for the low-volume, high-value pings.

☕ Support pingwa

Solo, self-funded, official Cloud API. If pingwa saves you a ban or a bridge headache, a coffee keeps the free tier free — entirely optional, and it unlocks nothing.

Sponsor on GitHub →

Not affiliated with Home Assistant or the Home Assistant Foundation. rest_command is a standard Home Assistant integration; see their own docs for the full option set. pingwa is an independent, self-hosted service. See about and privacy.