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

# Quickstart

> Send your first WhatsApp message in 5 minutes.

The Connexease Gateway sits between your application and the Meta WhatsApp Cloud API. You send a single HTTP request with your API key — the Gateway handles authentication with Meta, enforces rate limits, tracks billing, and returns a standard response. This guide walks you through the full flow from key creation to receiving your first delivery confirmation.

<CardGroup cols={2}>
  <Card title="Send a Message" icon="paper-plane" href="/api-reference/send-message">
    Text, media, and template message reference.
  </Card>

  <Card title="Set Up Webhooks" icon="webhook" href="/api-reference/webhooks">
    Receive incoming messages and delivery updates.
  </Card>

  <Card title="Authentication" icon="key" href="/essentials/authentication">
    API key management and webhook security.
  </Card>

  <Card title="Error Codes" icon="triangle-exclamation" href="/api-reference/error-codes">
    All error codes with resolution steps.
  </Card>
</CardGroup>

***

## Step 1 — Get Your API Key

Sign in to the [Connexease Gateway Dashboard](https://gateway.connexease.com) → **App → Developers → Create API Key**.

You'll receive a key prefixed with `pk_` for production or `sk_` for staging. Keep it in an environment variable — never commit it to source control.

<Warning>
  Never expose your API key in frontend code, mobile apps, or public repositories. All requests must come from your backend server.
</Warning>

***

## Step 2 — Test in Sandbox

Before touching a real WhatsApp number, use `is_fake=true` to verify your integration end-to-end. The full pipeline runs — auth is checked, rate limits apply, billing balance is validated — but the Meta API call is skipped and a fake message ID is returned.

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST "https://api.gateway.connexease.com/v1/wa/message?is_fake=true" \
    -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
    -H "Content-Type: application/json" \
    -d '{
      "messaging_product": "whatsapp",
      "to": "905321234567",
      "type": "text",
      "text": { "body": "Hello! This is a test." }
    }'
  ```

  ```python Python theme={null}
  import requests

  response = requests.post(
      "https://api.gateway.connexease.com/v1/wa/message",
      params={"is_fake": "true"},
      headers={
          "Authorization": "Bearer sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
          "Content-Type": "application/json",
      },
      json={
          "messaging_product": "whatsapp",
          "to": "905321234567",
          "type": "text",
          "text": {"body": "Hello! This is a test."}
      }
  )
  print(response.json())
  ```

  ```javascript Node.js theme={null}
  const response = await fetch(
    'https://api.gateway.connexease.com/v1/wa/message?is_fake=true',
    {
      method: 'POST',
      headers: {
        'Authorization': 'Bearer sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        messaging_product: 'whatsapp',
        to: '905321234567',
        type: 'text',
        text: { body: 'Hello! This is a test.' }
      }),
    }
  );
  console.log(await response.json());
  ```

  ```go Go theme={null}
  payload := map[string]any{
      "messaging_product": "whatsapp",
      "to":   "905321234567",
      "type": "text",
      "text": map[string]any{"body": "Hello! This is a test."},
  }
  body, _ := json.Marshal(payload)

  req, _ := http.NewRequest("POST",
      "https://api.gateway.connexease.com/v1/wa/message?is_fake=true",
      bytes.NewReader(body),
  )
  req.Header.Set("Authorization", "Bearer sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")
  req.Header.Set("Content-Type", "application/json")
  http.DefaultClient.Do(req)
  ```
</CodeGroup>

**Response:**

```json theme={null}
{
  "isSuccess": true,
  "data": {
    "messaging_product": "whatsapp",
    "messages": [
      { "id": "wamid.FAKE_1711900000000000000" }
    ]
  }
}
```

***

## Step 3 — Send a Real Message

Switch to your production key (`pk_`), remove `is_fake`, and use a real recipient number. Phone numbers must include the country code without `+`, spaces, or dashes — e.g. `905321234567` or `14155552671`.

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://api.gateway.connexease.com/v1/wa/message \
    -H "Authorization: Bearer pk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
    -H "Content-Type: application/json" \
    -d '{
      "messaging_product": "whatsapp",
      "to": "905321234567",
      "type": "text",
      "text": { "body": "Hello! Your order has been confirmed." }
    }'
  ```

  ```python Python theme={null}
  import requests

  response = requests.post(
      "https://api.gateway.connexease.com/v1/wa/message",
      headers={
          "Authorization": "Bearer pk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
          "Content-Type": "application/json",
      },
      json={
          "messaging_product": "whatsapp",
          "to": "905321234567",
          "type": "text",
          "text": {"body": "Hello! Your order has been confirmed."}
      }
  )
  print(response.json())
  ```

  ```javascript Node.js theme={null}
  const response = await fetch('https://api.gateway.connexease.com/v1/wa/message', {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer pk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      messaging_product: 'whatsapp',
      to: '905321234567',
      type: 'text',
      text: { body: 'Hello! Your order has been confirmed.' }
    }),
  });
  console.log(await response.json());
  ```
</CodeGroup>

**Response:**

```json theme={null}
{
  "isSuccess": true,
  "data": {
    "messaging_product": "whatsapp",
    "contacts": [
      { "input": "905321234567", "wa_id": "905321234567" }
    ],
    "messages": [
      { "id": "wamid.HBgNOTA1Mzk5ODc2NTQzFQIAERgSM0Y3RDg5..." }
    ]
  }
}
```

<Tip>
  Store `data.messages[0].id` — the `wamid` — in your database. You'll use it to match incoming delivery status webhooks in Step 5.
</Tip>

***

## Step 4 — Set Up Your Webhook Endpoint

Go to [Dashboard](https://gateway.connexease.com) → **Settings → Webhooks**, enter your HTTPS URL, set a webhook secret, and select the events you want to receive.

| Event                     | Description                                       |
| ------------------------- | ------------------------------------------------- |
| `messages`                | A user sent a message to your number              |
| `message_status`          | Delivery status changed (sent, delivered, failed) |
| `read`                    | A user read your message                          |
| `message_template_status` | Template approved or rejected                     |
| `account`                 | Account or phone number update                    |

Your endpoint must return **HTTP 200 within 5 seconds**. Process events asynchronously.

<CodeGroup>
  ```javascript Node.js theme={null}
  app.post('/webhook', (req, res) => {
    const auth = req.headers['authorization'];
    if (auth !== `Bearer ${process.env.WEBHOOK_SECRET}`) {
      return res.status(401).send('Unauthorized');
    }
    res.sendStatus(200);
    setImmediate(() => processEvent(req.body));
  });

  function processEvent(body) {
    const changes = body?.entry?.[0]?.changes ?? [];
    for (const change of changes) {
      const value = change.value;
      for (const msg of value?.messages ?? []) {
        console.log(`[${msg.type}] from ${msg.from}`);
      }
      for (const status of value?.statuses ?? []) {
        console.log(`${status.id} → ${status.status}`);
      }
    }
  }
  ```

  ```python Python theme={null}
  @app.route('/webhook', methods=['POST'])
  def webhook():
      if request.headers.get('Authorization') != f"Bearer {os.environ['WEBHOOK_SECRET']}":
          return '', 401
      payload = request.get_json()
      threading.Thread(target=process_event, args=(payload,), daemon=True).start()
      return '', 200

  def process_event(body):
      changes = body.get('entry', [{}])[0].get('changes', [])
      for change in changes:
          value = change.get('value', {})
          for msg in value.get('messages', []):
              print(f"[{msg['type']}] from {msg['from']}")
          for status in value.get('statuses', []):
              print(f"{status['id']} → {status['status']}")
  ```
</CodeGroup>

***

## Step 5 — Track Delivery Status

Once your webhook is live, the Gateway will POST a `message_status` event every time the delivery state of a message changes. Match it to your original send using the `wamid`.

```json theme={null}
{
  "entry": [{
    "changes": [{
      "field": "messages",
      "value": {
        "statuses": [{
          "id": "wamid.HBgNOTA1Mzk5ODc2NTQzFQ...",
          "status": "delivered",
          "timestamp": "1711900450",
          "recipient_id": "905321234567"
        }]
      }
    }]
  }]
}
```

<Warning>
  `isSuccess: true` on the send response means the message was **accepted**, not delivered. `delivered` only arrives via webhook.
</Warning>

***

## Next Steps

<CardGroup cols={2}>
  <Card title="Template Messages" icon="file-lines" href="/api-reference/send-message">
    Use approved templates to start new conversations.
  </Card>

  <Card title="All Webhook Events" icon="bolt" href="/api-reference/webhooks">
    Full payload examples for every event type.
  </Card>

  <Card title="Error Handling" icon="shield-exclamation" href="/api-reference/error-codes">
    Every error code with recommended actions.
  </Card>

  <Card title="Billing" icon="credit-card" href="/essentials/billing-and-pricing">
    How Connexease and Meta fees work.
  </Card>
</CardGroup>
