> ## Documentation Index
> Fetch the complete documentation index at: https://docs.tawked.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Notifications quickstart

> Send your first WhatsApp message with Tawked Notifications: connect your number, create a live key with notifications:send, send Meta's hello_world to your phone, read its status, then send your own template.

At the end of this page your number has sent a WhatsApp message to your own phone through the API, and you know how to send your own template with its values.

<Prompt description="Ask your coding assistant to add Tawked Notifications to your project." actions={["copy", "cursor"]}>
  Add WhatsApp notifications to this project with Tawked Notifications (docs: [https://docs.tawked.com/whatsapp/quickstart](https://docs.tawked.com/whatsapp/quickstart), reference: [https://tawked.com/openapi.json](https://tawked.com/openapi.json)).

  * Read the key from the environment variable TAWKED\_KEY, on the server only. Never send it to a browser or a mobile app.
  * List the approved templates with GET [https://tawked.com/v1/whatsapp/templates](https://tawked.com/v1/whatsapp/templates) and use the placeholders each one declares.
  * Send with POST [https://tawked.com/v1/whatsapp/messages](https://tawked.com/v1/whatsapp/messages): to (a Saudi mobile), template, lang, params, and header or buttons when the template has them. Send an Idempotency-Key per business event and retry a 502 or a network error with the same key.
  * Store the returned id next to the order or event, and update the status from message.\* webhooks (verify the tawked-signature header) or GET /v1/whatsapp/messages/ID.
  * Handle 422 errors by their error field (unknown\_template, template\_not\_approved, invalid\_params, consent\_opted\_out) without retrying them.
</Prompt>

**Before you start**

* A Tawked account with an application that has Notifications on, in review or approved. [Sign up](https://tawked.com/en/signup) if you have none.
* The owner or an admin of the account, to connect the number.
* A WhatsApp number you control, and a Facebook account that manages your business at Meta.

<Steps>
  <Step title="Connect your number">
    Open the application, then **Notifications → Overview**, and press **Connect WhatsApp**. The console asks where the number is today and the details customers will see, then Meta opens its window: pick or create the business and the number, and confirm it by SMS or a call. Tawked registers the number and opens its Tawked Chat inbox.

    Meta sends nothing until the WhatsApp Business Account has a payment method. Add a card to that account in Meta and make it the default; the Overview tells you when it finds one.
  </Step>

  <Step title="Create a live key">
    On the application's **API keys** page, press **Create a key**. Choose the type **Live**, and under **Access** either **All products** or **Custom** with Notifications set to **Send** (the `notifications:send` scope). Copy the key: it shows once. Put it in your server's environment as `TAWKED_KEY`.

    A test key does not work here: every WhatsApp endpoint answers it `403 live_key_required`. A live key works while the application is in review, because review holds Verify codes only.
  </Step>

  <Step title="Send Meta's hello_world to your phone">
    Most new WhatsApp Business Accounts come with Meta's `hello_world` template already approved, in `en_US`, with no placeholders. Send it to your own phone:

    <CodeGroup>
      ```bash cURL theme={"dark"}
      curl -X POST https://tawked.com/v1/whatsapp/messages \
        -H "Authorization: Bearer $TAWKED_KEY" \
        -H "Content-Type: application/json" \
        -d '{ "to": "0551234567", "template": "hello_world", "lang": "en_US" }'
      ```

      ```javascript Node.js theme={"dark"}
      const res = await fetch('https://tawked.com/v1/whatsapp/messages', {
        method: 'POST',
        headers: {
          Authorization: `Bearer ${process.env.TAWKED_KEY}`,
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({ to: '0551234567', template: 'hello_world', lang: 'en_US' }),
      });
      const message = await res.json(); // keep message.id to read the status
      ```

      ```php PHP theme={"dark"}
      $res = Http::withToken(env('TAWKED_KEY'))
          ->post('https://tawked.com/v1/whatsapp/messages', [
              'to' => '0551234567',
              'template' => 'hello_world',
              'lang' => 'en_US',
          ]);
      $id = $res->json('id'); // keep the id to read the status
      ```

      ```python Python theme={"dark"}
      import os, requests

      res = requests.post(
          "https://tawked.com/v1/whatsapp/messages",
          headers={"Authorization": f"Bearer {os.environ['TAWKED_KEY']}"},
          json={"to": "0551234567", "template": "hello_world", "lang": "en_US"},
      )
      message_id = res.json()["id"]  # keep the id to read the status
      ```
    </CodeGroup>

    The answer is `202 Accepted`: Meta has taken the message, and it reaches your phone in seconds.

    ```json theme={"dark"}
    {
      "id": "0f4c9c0e-6d2b-4b8a-9c3e-7a1d2e3f4a5b",
      "status": "accepted",
      "to": "+966551234567",
      "template": "hello_world",
      "lang": "en_US",
      "reference": null,
      "price_halalas": 0,
      "created_at": "2026-09-06T12:00:00+03:00"
    }
    ```

    `price_halalas` is the fee this send took from your balance, at the price on [tawked.com/en/pricing](https://tawked.com/en/pricing). If your account has no `hello_world`, skip to step 5 with a template of your own.

    The likely refusals: `403 insufficient_scope` (the key's access does not include Notifications send), `409 no_whatsapp_number` (the number is not connected to this key's application), `422 unknown_template`. Every code is on [Errors](/errors).
  </Step>

  <Step title="Read the status">
    Statuses arrive from Meta within about a minute: `accepted`, then `sent`, `delivered`, `read`, or `failed`.

    <CodeGroup>
      ```bash cURL theme={"dark"}
      curl https://tawked.com/v1/whatsapp/messages/0f4c9c0e-6d2b-4b8a-9c3e-7a1d2e3f4a5b \
        -H "Authorization: Bearer $TAWKED_KEY"
      ```

      ```javascript Node.js theme={"dark"}
      const res = await fetch(`https://tawked.com/v1/whatsapp/messages/${message.id}`, {
        headers: { Authorization: `Bearer ${process.env.TAWKED_KEY}` },
      });
      const { status, error } = await res.json();
      ```

      ```php PHP theme={"dark"}
      $message = Http::withToken(env('TAWKED_KEY'))
          ->get("https://tawked.com/v1/whatsapp/messages/{$id}")
          ->json();
      ```

      ```python Python theme={"dark"}
      res = requests.get(
          f"https://tawked.com/v1/whatsapp/messages/{message_id}",
          headers={"Authorization": f"Bearer {os.environ['TAWKED_KEY']}"},
      )
      status = res.json()["status"]
      ```
    </CodeGroup>

    ```json theme={"dark"}
    {
      "id": "0f4c9c0e-6d2b-4b8a-9c3e-7a1d2e3f4a5b",
      "status": "delivered",
      "to": "+966551234567",
      "template": "hello_world",
      "lang": "en_US",
      "reference": null,
      "price_halalas": 0,
      "error": null,
      "created_at": "2026-09-06T12:00:00+03:00",
      "sent_at": "2026-09-06T12:00:01+03:00",
      "delivered_at": "2026-09-06T12:00:04+03:00",
      "read_at": null,
      "failed_at": null
    }
    ```

    In production, receive the `message.*` [webhooks](/webhooks) instead of polling. A `failed` message carries Meta's code and message in `error`, and its fee is refunded.
  </Step>

  <Step title="Send your own template">
    Create a template on **Notifications → Templates** and wait for Meta to approve it, usually within minutes. Then list your templates to see the values each one expects:

    ```bash theme={"dark"}
    curl https://tawked.com/v1/whatsapp/templates \
      -H "Authorization: Bearer $TAWKED_KEY"
    ```

    ```json theme={"dark"}
    {
      "data": [
        {
          "name": "order_received_v1",
          "language": "ar",
          "category": "UTILITY",
          "status": "APPROVED",
          "placeholders": {
            "kind": "named",
            "header": [],
            "body": ["name", "order"],
            "buttons": [{ "index": 0, "type": "url" }]
          }
        }
      ]
    }
    ```

    Send it with one value per body placeholder in `params`, and one entry per URL button in `buttons`:

    <CodeGroup>
      ```bash cURL theme={"dark"}
      curl -X POST https://tawked.com/v1/whatsapp/messages \
        -H "Authorization: Bearer $TAWKED_KEY" \
        -H "Content-Type: application/json" \
        -H "Idempotency-Key: order-1042-received" \
        -d '{
          "to": "0551234567",
          "template": "order_received_v1",
          "lang": "ar",
          "params": { "name": "أحمد", "order": "1042" },
          "buttons": [{ "index": 0, "parameter": "1042" }],
          "reference": "order-1042"
        }'
      ```

      ```javascript Node.js theme={"dark"}
      const res = await fetch('https://tawked.com/v1/whatsapp/messages', {
        method: 'POST',
        headers: {
          Authorization: `Bearer ${process.env.TAWKED_KEY}`,
          'Content-Type': 'application/json',
          'Idempotency-Key': 'order-1042-received',
        },
        body: JSON.stringify({
          to: '0551234567',
          template: 'order_received_v1',
          lang: 'ar',
          params: { name: 'أحمد', order: '1042' },
          buttons: [{ index: 0, parameter: '1042' }],
          reference: 'order-1042',
        }),
      });
      ```

      ```php PHP theme={"dark"}
      $res = Http::withToken(env('TAWKED_KEY'))
          ->withHeaders(['Idempotency-Key' => 'order-1042-received'])
          ->post('https://tawked.com/v1/whatsapp/messages', [
              'to' => '0551234567',
              'template' => 'order_received_v1',
              'lang' => 'ar',
              'params' => ['name' => 'أحمد', 'order' => '1042'],
              'buttons' => [['index' => 0, 'parameter' => '1042']],
              'reference' => 'order-1042',
          ]);
      ```

      ```python Python theme={"dark"}
      res = requests.post(
          "https://tawked.com/v1/whatsapp/messages",
          headers={
              "Authorization": f"Bearer {os.environ['TAWKED_KEY']}",
              "Idempotency-Key": "order-1042-received",
          },
          json={
              "to": "0551234567",
              "template": "order_received_v1",
              "lang": "ar",
              "params": {"name": "أحمد", "order": "1042"},
              "buttons": [{"index": 0, "parameter": "1042"}],
              "reference": "order-1042",
          },
      )
      ```
    </CodeGroup>

    The likely refusals: `422 template_not_approved` (Meta has not approved it yet; `message` carries its status), `422 invalid_params` (a value is missing, extra or has a newline; `message` names it). Neither is worth retrying as it is.
  </Step>
</Steps>

## Before real customers

* Send one `Idempotency-Key` per business event, and retry a `502` or a network error with the same key. See [Reliability and limits](/reliability#idempotency).
* Receive `message.*` [webhooks](/webhooks) and verify their signature.
* Keep enough balance for your sends, and set the **Low-balance alert** on **Wallet → Balance**.
* A marketing template never reaches a customer who wrote STOP to your number: it answers `422 consent_opted_out`. See [Marketing and opt-outs](/whatsapp/messages#marketing-and-opt-outs).

## Next

<CardGroup cols={2}>
  <Card title="Sending messages" icon="paper-plane" href="/whatsapp/messages">
    Text and image headers, authentication templates, statuses.
  </Card>

  <Card title="Templates" icon="file-lines" href="/whatsapp/templates">
    Categories, Meta's library, quality and pausing.
  </Card>

  <Card title="Webhooks" icon="bell" href="/webhooks">
    One signed event per status change.
  </Card>

  <Card title="Tawked Chat" icon="comments" href="/chat">
    Where your customers' replies land.
  </Card>
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.