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

# Webhooks

> Receive real-time NearIQ events via HTTP POST to your endpoint.

## How webhooks work

When NearIQ detects a competitive change, it can POST a JSON payload to a URL you register. This lets you build real-time integrations — send an alert to Slack, trigger a workflow, or update your own dashboard.

## Registering a webhook

```bash theme={null}
curl -X POST https://app.neariq.io/api/v1/webhooks \
  -H "X-NearIQ-Key: niq_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://yourapp.com/hooks/neariq",
    "events": ["competitor.rating_change", "competitor.review_surge"]
  }'
```

Webhook URLs must use HTTPS, must not include embedded credentials, and must be publicly routable; localhost, private, link-local, multicast, and reserved network hosts are rejected. NearIQ also re-checks DNS resolution before delivery and deactivates endpoints that resolve to non-public addresses. NearIQ generates and returns the signing secret once when the webhook is created.

Supported events are `competitor.rating_change`, `competitor.review_surge`, `competitor.hours_change`, `competitor.price_change`, `competitor.status_change`, `competitor.website_change`, `competitor.new_competitor`, `business.rating_change`, `business.review_surge`, `alert.created`, `api_key.suspended`, `api_key.reactivated`, and `api_key.revoked_by_admin`.

## Payload format

```json theme={null}
{
  "id": "0bff1ff0-98ab-4c2e-a3ee-4c0b39c090a1",
  "event": "competitor.rating_change",
  "createdAt": "2026-04-27T09:14:22Z",
  "data": {
    "alert": {
      "id": "8e0a8c1d-2a95-4d17-a96b-1ef6b47681c0",
      "type": "rating_change",
      "severity": "opportunity",
      "title": "Rival Pizza dropped from 4.6 to 4.3 stars",
      "description": "Recent reviews suggest service speed is becoming a weakness.",
      "recommendation": "Reply to your latest positive reviews and highlight fast pickup in your next post.",
      "createdAt": "2026-04-27T09:14:22Z",
      "isOwnBusiness": false,
      "metadata": null
    },
    "competitor": {
      "id": "comp_xyz",
      "name": "Rival Pizza",
      "placeId": "ChIJ..."
    }
  }
}
```

## Verifying signatures

NearIQ signs every webhook delivery using HMAC-SHA256. Verify the signature to ensure the request came from NearIQ:

```typescript theme={null}
import { createHmac } from 'crypto'

function verifyWebhook(payload: string, timestamp: string, signature: string, secret: string): boolean {
  const expected = createHmac('sha256', secret)
    .update(`${timestamp}.${payload}`)
    .digest('hex')
  return signature === `sha256=${expected}`
}

// In your webhook handler:
const sig = req.headers['x-neariq-signature']
const timestamp = req.headers['x-neariq-timestamp']
const raw = req.rawBody // unparsed request body string
if (!verifyWebhook(raw, timestamp, sig, process.env.NEARIQ_WEBHOOK_SECRET)) {
  return res.status(401).send('Invalid signature')
}
```

Every delivery includes `X-NearIQ-Delivery`, `X-NearIQ-Event`, `X-NearIQ-Timestamp`, and `X-NearIQ-Signature`. The signature uses the exact raw request body, prefixed by the timestamp.

## Retry behavior

NearIQ retries failed deliveries (non-2xx response or timeout) with exponential backoff:

* Retry delays start at about 1 minute
* Delays increase exponentially and cap at about 1 hour
* Deliveries are attempted up to 8 times

After the final attempt, the delivery is marked dead. The endpoint remains registered so you can fix it without recreating the secret.

You can review failed webhook deliveries from the dashboard alert details panel. The panel shows the event type, HTTP response status, retry count, next retry time, and a sanitized payload preview. After fixing your receiver, use the alert's retry action to queue failed or dead deliveries again.

## Webhook management endpoints

All webhook management endpoints require an API key with the `webhooks:manage` scope and a Growth+ plan.

### GET /webhooks — List webhooks

```bash theme={null}
curl https://app.neariq.io/api/v1/webhooks \
  -H "X-NearIQ-Key: niq_your_key_here"
```

```json theme={null}
{
  "webhooks": [
    {
      "id": "wh_abc123",
      "url": "https://yourapp.com/hooks/neariq",
      "events": ["competitor.rating_change", "competitor.review_surge"],
      "active": true,
      "createdAt": "2026-04-27T09:14:22Z",
      "lastTriggeredAt": "2026-05-01T12:00:00Z"
    }
  ]
}
```

### POST /webhooks — Register a webhook

```bash theme={null}
curl -X POST https://app.neariq.io/api/v1/webhooks \
  -H "X-NearIQ-Key: niq_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://yourapp.com/hooks/neariq",
    "events": ["competitor.rating_change", "alert.created"]
  }'
```

| Field    | Type      | Required | Notes                                                     |
| -------- | --------- | -------- | --------------------------------------------------------- |
| `url`    | string    | yes      | Must use HTTPS. No localhost, private, or reserved hosts. |
| `events` | string\[] | yes      | At least one event type. See supported events above.      |

```json theme={null}
{
  "webhook": {
    "id": "wh_abc123",
    "url": "https://yourapp.com/hooks/neariq",
    "events": ["competitor.rating_change", "alert.created"],
    "active": true,
    "secret": "whsec_abc123...xyz",
    "createdAt": "2026-05-01T12:00:00Z"
  }
}
```

The `secret` is returned only on creation. Store it securely — it cannot be retrieved again.

### PATCH /webhooks/:id — Update a webhook

```bash theme={null}
curl -X PATCH https://app.neariq.io/api/v1/webhooks/wh_abc123 \
  -H "X-NearIQ-Key: niq_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "events": ["competitor.rating_change", "competitor.review_surge", "alert.created"],
    "active": true
  }'
```

| Field    | Type      | Required | Notes                                             |
| -------- | --------- | -------- | ------------------------------------------------- |
| `url`    | string    | no       | New HTTPS endpoint URL.                           |
| `events` | string\[] | no       | Replace the event list.                           |
| `active` | boolean   | no       | Set `false` to pause deliveries without deleting. |

```json theme={null}
{
  "webhook": {
    "id": "wh_abc123",
    "url": "https://yourapp.com/hooks/neariq",
    "events": ["competitor.rating_change", "competitor.review_surge", "alert.created"],
    "active": true,
    "updatedAt": "2026-05-01T12:30:00Z"
  }
}
```

### DELETE /webhooks/:id — Remove a webhook

```bash theme={null}
curl -X DELETE https://app.neariq.io/api/v1/webhooks/wh_abc123 \
  -H "X-NearIQ-Key: niq_your_key_here"
```

```json theme={null}
{
  "deleted": true
}
```

Deleting a webhook is permanent. Pending deliveries for the endpoint are canceled.
