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

# Create a webhook subscription

> Register a URL to receive loyalty event notifications and get a signing secret.

Register an HTTPS endpoint to receive webhook deliveries for the events you select. Mage Loyalty signs every delivery with the signing secret returned here, so you can verify that requests are genuine.

<Warning>
  The `secret` is returned **only** in this `201 Created` response. It is shown once and never again. Store it securely. If you lose it, [rotate the secret](/api-reference/webhooks/subscriptions/rotate-secret) to issue a new one. See [Verifying webhook signatures](/api-reference/webhooks/verifying-signatures) for how to use it.
</Warning>

## Request body

| Field         | Type      | Required | Description                                                                                                                                       |
| ------------- | --------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
| `url`         | string    | Yes      | The HTTPS endpoint that will receive deliveries. Must be a valid URL                                                                              |
| `events`      | string\[] | Yes      | A non-empty array of events to subscribe to. Valid events: `points.earned`, `points.redeemed`, `customer.tier_upgrade`, `customer.tier_downgrade` |
| `description` | string    | No       | Optional label to help you identify the subscription                                                                                              |

## Response

Returns `201 Created` with the new subscription, including the `secret`.

## Errors

| Status | Scenario                                                                                                     |
| ------ | ------------------------------------------------------------------------------------------------------------ |
| `400`  | `url` missing, `url` not a valid URL, `events` empty or missing, one or more events invalid, or invalid JSON |
| `401`  | Missing or invalid API key                                                                                   |
| `403`  | The API key is read-only and cannot perform write operations                                                 |
| `429`  | [Rate limit](/api-reference/rate-limits) exceeded (6 requests/second)                                        |

<RequestExample>
  ```bash cURL theme={null}
  curl --request POST \
    --url https://api.mageloyalty.com/v1/webhook-subscriptions \
    --header 'Authorization: <api-key>' \
    --header 'Content-Type: application/json' \
    --data '{
    "url": "https://example.com/webhooks/mage",
    "events": ["points.earned", "customer.tier_upgrade"],
    "description": "Production points + tier sync"
  }'
  ```

  ```javascript Node theme={null}
  const response = await fetch("https://api.mageloyalty.com/v1/webhook-subscriptions", {
    method: "POST",
    headers: {
      Authorization: "<api-key>",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      url: "https://example.com/webhooks/mage",
      events: ["points.earned", "customer.tier_upgrade"],
      description: "Production points + tier sync",
    }),
  });

  const data = await response.json();
  ```

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

  response = requests.post(
      "https://api.mageloyalty.com/v1/webhook-subscriptions",
      headers={"Authorization": "<api-key>"},
      json={
          "url": "https://example.com/webhooks/mage",
          "events": ["points.earned", "customer.tier_upgrade"],
          "description": "Production points + tier sync",
      },
  )

  data = response.json()
  ```

  ```php PHP theme={null}
  <?php
  $ch = curl_init("https://api.mageloyalty.com/v1/webhook-subscriptions");
  curl_setopt_array($ch, [
      CURLOPT_POST => true,
      CURLOPT_RETURNTRANSFER => true,
      CURLOPT_HTTPHEADER => [
          "Authorization: <api-key>",
          "Content-Type: application/json",
      ],
      CURLOPT_POSTFIELDS => json_encode([
          "url" => "https://example.com/webhooks/mage",
          "events" => ["points.earned", "customer.tier_upgrade"],
          "description" => "Production points + tier sync",
      ]),
  ]);
  $data = json_decode(curl_exec($ch), true);
  ```
</RequestExample>

<ResponseExample>
  ```json 201 Created theme={null}
  {
    "data": {
      "type": "webhook_subscription",
      "id": "whsub_abc123",
      "attributes": {
        "url": "https://example.com/webhooks/mage",
        "events": ["points.earned", "customer.tier_upgrade"],
        "is_active": true,
        "description": "Production points + tier sync",
        "secret": "9f8a7b6c5d4e3f2a1b0c9d8e7f6a5b4c3d2e1f0a9b8c7d6e5f4a3b2c1d0e9f8a",
        "created_at": "2024-01-01T00:00:00.000Z",
        "updated_at": "2024-01-01T00:00:00.000Z"
      }
    }
  }
  ```

  ```json 400 Bad Request theme={null}
  {
    "errors": [
      {
        "status": "400",
        "title": "Bad Request",
        "detail": "url is required"
      }
    ]
  }
  ```

  ```json 400 Invalid URL theme={null}
  {
    "errors": [
      {
        "status": "400",
        "title": "Bad Request",
        "detail": "url must be a valid URL"
      }
    ]
  }
  ```

  ```json 400 Empty events theme={null}
  {
    "errors": [
      {
        "status": "400",
        "title": "Bad Request",
        "detail": "events must be a non-empty array"
      }
    ]
  }
  ```

  ```json 400 Invalid events theme={null}
  {
    "errors": [
      {
        "status": "400",
        "title": "Bad Request",
        "detail": "Invalid event(s): points.created. Valid events: points.earned, points.redeemed, customer.tier_upgrade, customer.tier_downgrade"
      }
    ]
  }
  ```
</ResponseExample>
