Skip to content

Connecting channels

Voxa connects to WhatsApp via Meta’s WhatsApp Business Cloud API. This guide walks through everything: Meta prerequisites, generating a long-lived access token, pasting credentials into Voxa, verifying the webhook, and testing.

You need all of the following in Meta Business Manager before starting:

  1. A Business Manager account (verified business ID).
  2. A WhatsApp Business Account (WABA) inside the Business Manager.
  3. A phone number registered against the WABA. It must be a number you own and control — Meta will send an SMS or voice verification code.
  4. A Meta App of type Business with the WhatsApp product added.
  5. A System User with Admin access to the WABA.

If any of those are missing, complete them in business.facebook.com before continuing. Meta’s own docs cover each step in detail; we don’t try to duplicate them here.

Voxa stores five values, all encrypted at rest:

FieldWhere to find it
app_idMeta app dashboard → Settings → Basic.
app_secretMeta app dashboard → Settings → Basic → Show secret.
phone_number_idMeta app → WhatsApp → API Setup → Phone numbers table.
waba_idMeta app → WhatsApp → API Setup → WhatsApp Business Account ID.
access_tokenSystem User access token (see below).

The temporary token on the API Setup page expires in 24 hours — don’t use it in production. Instead:

  1. Business Manager → Business Settings → Users → System Users. Create a System User (or reuse an existing one).

  2. Grant it asset access to the WhatsApp Business Account as Admin. Without this, the token won’t have permission to send messages.

  3. Click “Generate new token” on the system user. Choose your Meta App, then select the permissions whatsapp_business_management and whatsapp_business_messaging. Leave Never expire checked.

  4. Copy the token immediately. Meta will only show it once.

Voxa needs Meta to POST inbound messages and status updates to a webhook URL that Voxa exposes.

  1. Meta app dashboard → WhatsApp → Configuration → Webhook.

  2. Callback URL — paste the URL shown on Voxa’s Settings → Meta credentials screen. It has this shape:

    https://voxa.software/webhooks/whatsapp/<opaque-token>

    The opaque token is specific to your tenant and non-enumerable.

  3. Verify Token — paste the verify token from Voxa’s settings page. Meta uses this to prove to Voxa that the callback belongs to your Meta app; Voxa stores it plaintext in meta_credentials.

  4. Verify and Save. Meta issues a GET with the challenge; Voxa’s webhook handshakes it in under 50 ms.

  5. Subscribe to webhook fields. Tick at minimum:

    • messages (inbound text, media, button clicks, status callbacks)
    • Optional: message_template_status_update if you plan to manage templates through Meta.
  1. In Voxa → Settings → Meta credentials.
  2. Paste each of the five values.
  3. Click Save. Voxa encrypts the five secret fields (app_secret, access_token) with AES-256-GCM keyed off CREDENTIAL_ENCRYPTION_KEY before inserting the row.
  4. Click Test connection. Voxa calls Meta’s /v21.0/<phone_number_id> endpoint and reports the WABA display name and phone number. A green check appears if the round-trip succeeds; last_test_at and last_test_status are recorded for audit.

Every inbound webhook POST carries an X-Hub-Signature-256 header. Voxa computes an HMAC-SHA256 of the raw body keyed off your stored app_secret and compares it with the header using timingSafeEqual.

If a mismatch occurs:

  • The request is rejected with 403.
  • A signature_valid: false entry lands in webhook_events.
  • An owner-level in-app notification fires alerting you to a probable misconfiguration (wrong app_secret or wrong Meta app).

This is by design: a working webhook with an invalid signature means something is trying to impersonate Meta against your tenant, and you should notice.

  1. Open a Voxa quickstart flow on a real WhatsApp account that is not the one attached to your tenant.

  2. Reply to the welcome message with any text.

  3. Open Conversations in the Voxa dashboard. You should see the inbound message within a few seconds.

  4. Check Audit log — you’ll see a webhook.inbound.received event.

  5. Check Settings → Meta credentials → Recent webhook events. Every inbound POST in the last 24 hours shows up with the signature status.

SymptomLikely cause
Webhook verify failsVerify token mismatch between Voxa and Meta.
Inbound messages never arriveWebhook fields not subscribed in Meta.
signature_valid: false in recent eventsWrong app_secret pasted, or the Meta app was swapped.
Test connection fails with 401Access token revoked or permissions missing. Regenerate.
Test connection fails with 190Token expired — you used a temporary 24-hour token. Generate a system-user token.