> ## 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.

# Authentication

> How to authenticate your requests and secure your webhook endpoint.

The Connexease Gateway uses API keys to verify your identity on every outbound request. When the Gateway forwards events back to your server, it uses a webhook secret you define — so both directions are protected without any extra setup on your end.

***

## API Key Authentication

Every request to `/v1/wa/message` must include your API key in the `Authorization` header. The Gateway checks this key before processing anything — rate limiting, billing, and message delivery all happen only after a valid key is confirmed.

```http theme={null}
Authorization: Bearer YOUR_API_KEY
```

Get your API key from the [Connexease Gateway Dashboard](https://gateway.connexease.com) → **App → Developers → API Keys → Create API Key**.

API keys are prefixed so you can tell them apart at a glance:

| Prefix | Environment           |
| ------ | --------------------- |
| `pk_`  | Production            |
| `sk_`  | Staging / Development |

<Warning>
  Never expose your API key in frontend JavaScript, mobile app code, or public repositories. Always make requests from your backend server.
</Warning>

### Example

<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!" }
    }'
  ```

  ```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!"}
      }
  )
  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!' }
    }),
  });
  console.log(await response.json());
  ```

  ```go Go theme={null}
  req, _ := http.NewRequest("POST",
      "https://api.gateway.connexease.com/v1/wa/message",
      strings.NewReader(`{"messaging_product":"whatsapp","to":"905321234567","type":"text","text":{"body":"Hello!"}}`),
  )
  req.Header.Set("Authorization", "Bearer pk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")
  req.Header.Set("Content-Type", "application/json")
  http.DefaultClient.Do(req)
  ```
</CodeGroup>

### Error Responses

If authentication fails, the Gateway returns one of the following errors before touching any other part of the pipeline:

| Code       | HTTP | Cause                                   | Fix                                    |
| ---------- | ---- | --------------------------------------- | -------------------------------------- |
| `AUTH_002` | 401  | `Authorization` header missing entirely | Add the header to every request        |
| `AUTH_003` | 401  | Not in `Bearer <token>` format          | Ensure the `Bearer ` prefix is present |
| `AUTH_001` | 401  | Key not found or expired                | Verify the key in Dashboard → API Keys |

***

## Public API Authentication

The Public API (`public-api.gateway.connexease.com`) endpoints authenticate with a **secret key** (`sk_`), sent in the `Authorization` header as a Bearer token. The organization is always derived from the credential — you never pass `organization_id` separately.

### Secret Key

A server-side secret used for the Analytics, Application, and Template endpoints. Send it as:

```http theme={null}
Authorization: Bearer sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
```

The Secret Key is provided via email. To request your key, please contact the Connexease Sales or Support team, or send an email request to [**abdullah@connexease.com**](mailto:abdullah@connexease.com). The organization (and the secret's identity) is derived from the key.

<Warning>
  The secret key grants full server-side access. Never expose it in frontend JavaScript, mobile apps, or public repositories — use it only from your backend.
</Warning>

```bash theme={null}
curl -X GET "https://public-api.gateway.connexease.com/public/api/v1/wa/analytics/messages" \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
```

**Used by:** [Get Messages](/public-api-reference/analytics/get-messages), [Get Business Profile](/public-api-reference/application/get-business-profile), [Update Business Profile](/public-api-reference/application/update-business-profile), [Create Template](/public-api-reference/template/create-template), [Get Templates](/public-api-reference/template/get-templates), [Get Template Detail](/public-api-reference/template/get-template-detail), and [Update Template](/public-api-reference/template/update-template).

**Errors:** `ORGANIZATION_SECRET_010` (missing), `ORGANIZATION_SECRET_011` (invalid).

***

## Securing Your Webhook Endpoint

When the Gateway forwards events to your server, it includes a secret in the `Authorization` header — the same secret you set in **Dashboard → Settings → Webhooks**. This lets you confirm that the request genuinely came from the Gateway and not a third party.

Your endpoint receives requests in this shape:

```http theme={null}
POST https://your-server.com/webhook
Content-Type: application/json
Authorization: Bearer YOUR_WEBHOOK_SECRET

{ ...event payload... }
```

Check this header at the top of your handler, before reading or acting on the payload. Respond with HTTP 200 immediately, then process the event asynchronously — the Gateway will retry if it doesn't hear back within 5 seconds.

<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(() => handleEvent(req.body));
  });
  ```

  ```python Python theme={null}
  @app.route('/webhook', methods=['POST'])
  def webhook():
      auth = request.headers.get('Authorization', '')
      if auth != f"Bearer {os.environ['WEBHOOK_SECRET']}":
          return '', 401

      payload = request.get_json()
      threading.Thread(target=handle_event, args=(payload,), daemon=True).start()
      return '', 200
  ```

  ```go Go theme={null}
  func webhookHandler(w http.ResponseWriter, r *http.Request) {
      if r.Header.Get("Authorization") != "Bearer "+os.Getenv("WEBHOOK_SECRET") {
          http.Error(w, "Unauthorized", http.StatusUnauthorized)
          return
      }
      body, _ := io.ReadAll(r.Body)
      w.WriteHeader(http.StatusOK)
      go handleEvent(body)
  }
  ```
</CodeGroup>

<Note>
  Use a strong, randomly generated string (minimum 32 characters) as your webhook secret. Set it in [Dashboard](https://gateway.connexease.com) → Settings → Webhooks.
</Note>

***

## API Key Management

### Creating and Revoking Keys

Keys are created and managed from [Dashboard](https://gateway.connexease.com) → **Settings → API Keys**. If a key is compromised, revoke it immediately and generate a new one — update your environment variables before restarting your service.

### Best Practices

* Use separate keys for production (`pk_`) and staging (`sk_`) environments.
* Pass keys via environment variables — never hardcode them in source files.
* Enable secret scanning in your CI/CD pipeline to catch accidental commits.

```bash theme={null}
# .env.production
CONNEXEASE_API_KEY=pk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

# .env.staging
CONNEXEASE_API_KEY=sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
```
