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

# Webhook Payloads

This document describes the webhook payloads that are sent when subscription alerts are triggered for the `/subscriptions` endpoint.

## Overview

When you create a subscription with webhook channels configured, Nevua Markets will send HTTP POST requests to your configured webhook URLs when the subscription conditions are met. There are two types of notifications:

1. **Price Notifications** - Sent when price-based alert conditions are met (e.g., crossing thresholds)
2. **Event Status Notifications** - Sent when event or market status changes occur (e.g., new events created, markets closed)

## Price Notification Schema

This schema is used for all price-based alert notifications.

#### Properties

| Field                    | Type                                 | Description                                                 |
| ------------------------ | ------------------------------------ | ----------------------------------------------------------- |
| `type`                   | `"price_notification"`               | The notification type                                       |
| `userId`                 | `string`                             | The ID of the user who owns the subscription                |
| `createdAt`              | `string` (ISO 8601)                  | When the notification was created                           |
| `subscriptionId`         | `string`                             | The ID of the subscription that triggered this notification |
| `watchlistId`            | `string`                             | The ID of the watchlist being monitored                     |
| `watchlistName`          | `string`                             | The name of the watchlist                                   |
| `eventId`                | `string`                             | The Polymarket event ID                                     |
| `eventTitle`             | `string`                             | The title of the event                                      |
| `marketId`               | `string`                             | The Polymarket market ID                                    |
| `marketQuestion`         | `string`                             | The market question/title                                   |
| `polymarketSlug`         | `string`                             | The Polymarket URL slug for this event                      |
| `clobTokenId`            | `string`                             | The CLOB token identifier                                   |
| `subscriptionScope`      | `"Watchlist" \| "Event" \| "Market"` | The scope of the subscription                               |
| `subscriptionTypeConfig` | `object`                             | Configuration details for the subscription type             |
| `triggerType`            | `"One Time" \| "Recurring"`          | Whether this is a one-time or recurring trigger             |
| `detectedValue`          | `number`                             | The price/percentage value that triggered the alert         |
| `detectedAt`             | `string` (ISO 8601)                  | When the condition was detected                             |
| `detectedAtMs`           | `number`                             | Detection timestamp in milliseconds                         |
| `sentFromPolymarketAtMs` | `number`                             | When the data was received from Polymarket (milliseconds)   |
| `channels`               | `array`                              | Array of notification channels used for delivery            |
| `detectionDetails`       | `object`                             | \[Optional] Additional detection metadata                   |
| `polymarketSourceEvent`  | `object`                             | \[Optional] Raw source event data from Polymarket           |

Changelog:

* \[30/09/2025]: `subscriptionTypeConfig` will soon be migrated to a `rules` object, which will also
  contain trigger context.

#### Example Price Notification

```json theme={null}
{
  "type": "price_notification",
  "userId": "67d1ac50ff34ab5a5ab571fe",
  "createdAt": "2025-09-30T12:48:14.109Z",
  "watchlistId": "68dbd18b92cd0e76ed506d16",
  "watchlistName": "Test Watchlist",
  "eventId": "32228",
  "eventTitle": "Balance of Power: 2026 Midterms",
  "marketId": "562828",
  "marketQuestion": "2026 Balance of Power: D Senate, D House",
  "polymarketSlug": "balance-of-power-2026-midterms",
  "subscriptionId": "68dbd18c92cd0e76ed506d18",
  "clobTokenId": "34722410608062854697106861099776685947172185964394483545370684749662285977831",
  "subscriptionScope": "Watchlist",
  "subscriptionTypeConfig": {
    "type": "Less Than",
    "config": {
      "params": {
        "threshold_percent": 90
      }
    }
  },
  "triggerType": "One Time",
  "detectedValue": 0.235,
  "detectionDetails": {
    "detectedValue": 0.235,
    "detectedTimeMs": 1759236494109,
    "priceChangeTimeMs": "1759236494020"
  },
  "sentFromPolymarketAtMs": 1759236494020,
  "detectedAt": "2025-09-30T12:48:14.109Z",
  "detectedAtMs": 1759236494109,
  "channels": [
    {
      "type": "Webhook",
      "settings": {
        "webhookUrl": "https://dev-webhook.nevua.markets/webhook"
      }
    }
  ],
  "polymarketSourceEvent": {
    "market": "0x16c63b7cc37f012b9f59ee164ec03877914c701d06d48291ae8d6fc08a088b0d",
    "price_changes": [
      {
        "asset_id": "34722410608062854697106861099776685947172185964394483545370684749662285977831",
        "price": "0.04",
        "size": "0",
        "side": "BUY",
        "hash": "e364191ad922c97239ce0f5ebc20fdabff098c98",
        "best_bid": "0.23",
        "best_ask": "0.24"
      }
    ],
    "timestamp": "1759236494020",
    "event_type": "price_change"
  },
  "_id": "68dbd18ef6ae9b7dfa90d219"
}
```

## Event Status Notification Schema

This schema is used for event and market status change notifications.

There are three types of event notifications:

* Open Markets, with `eventStatusScope`: `Market` and `triggerType`: `Open`
* Closed Markets, with `eventStatusScope`: `Market` and `triggerType`: `Closed`
* Closed Events, with `eventStatusScope`: `Event` and `triggerType`: `Closed`

If a closed event has only one market, then the webhook call will include that singular market
context, i.e. its id, question and outcome.

For new events with multiple markets, then a separate webhook call will be made for each market of
that event.

#### Properties

| Field              | Type                          | Description                                                        |
| ------------------ | ----------------------------- | ------------------------------------------------------------------ |
| `type`             | `"event_status_notification"` | The notification type                                              |
| `userId`           | `string`                      | The ID of the user who owns the subscription                       |
| `eventStatusScope` | `"Market" \| "Event"`         | Whether this is a market-level or event-level status change        |
| `triggerType`      | `"Open" \| "Closed"`          | Whether this is for opening or closing                             |
| `createdAt`        | `string` (ISO 8601)           | When the notification was created                                  |
| `subscriptionId`   | `string`                      | The ID of the subscription that triggered this notification        |
| `watchlistId`      | `string`                      | The ID of the watchlist being monitored                            |
| `watchlistName`    | `string`                      | The name of the watchlist                                          |
| `eventId`          | `string`                      | The Polymarket event ID                                            |
| `eventTitle`       | `string`                      | The title of the event                                             |
| `marketId`         | `string`                      | \[Optional] The market ID (present for market-level changes)       |
| `marketQuestion`   | `string`                      | \[Optional] The market question (present for market-level changes) |
| `outcomes`         | `string`                      | \[Optional] Available outcome options for the market               |
| `outcomePrices`    | `string`                      | \[Optional] Current prices for market outcomes                     |
| `polymarketSlug`   | `string`                      | The Polymarket URL slug for this event                             |
| `detectedAt`       | `string` (ISO 8601)           | When the status change was detected                                |
| `detectedAtMs`     | `number`                      | Detection timestamp in milliseconds                                |
| `channels`         | `array`                       | Array of notification channels used for delivery                   |

#### Example Event Status Notifications

**New Market Created**

```json theme={null}
{
  "type": "event_status_notification",
  "eventStatusScope": "Market",
  "triggerType": "Open",
  "userId": "68ac76f15d97fa94e41ddf6a",
  "createdAt": "2025-09-30T12:48:14.109Z",
  "subscriptionId": "68ac770c5d97fa94e41ddf6f",
  "watchlistId": "68ac770c5d97fa94e41ddf6e",
  "watchlistName": "Esport Arena Highlights and Competitive Scenes",
  "eventId": "40884",
  "eventTitle": "League of Legends: Gen.G Global Academy vs. DN Freecs Challengers",
  "marketId": "584650",
  "marketQuestion": "League of Legends: Gen.G Global Academy vs. DN Freecs Challengers"
  "polymarketSlug": "league-of-legends-geng-global-academy-vs-dn-freecs-challengers",
  "detectedAt": "2025-09-01T01:58:41.129Z",
  "detectedAtMs": 1756691921129,
  "channels": [
    {
      "type": "Webhook",
      "settings": {
        "webhookUrl": "https://dev-webhook.nevua.markets/webhook"
      }
    }
  ]
}
```

**Market Closed**

```json theme={null}
{
  "type": "event_status_notification",
  "eventStatusScope": "Market",
  "triggerType": "Closed",
  "userId": "6850f3944f12f220ecc25514",
  "createdAt": "2025-09-30T12:48:14.109Z",
  "subscriptionId": "6850f41e4f12f220ecc25518",
  "watchlistId": "6850f41e4f12f220ecc25517",
  "watchlistName": "sports",
  "eventId": "40057",
  "eventTitle": "CS2: BLAST Open London 2025",
  "marketId": "582357",
  "marketQuestion": "Will GamerLegion win the BLAST Open London 2025 tournament?",
  "outcomes": "[\"Yes\", \"No\"]",
  "outcomePrices": "[\"0\", \"1\"]"
  "polymarketSlug": "cs2-blast-open-london-2025",
  "detectedAt": "2025-08-31T16:19:39.020Z",
  "detectedAtMs": 1756657179020,
  "channels": [
    {
      "type": "Webhook",
      "settings": {
        "webhookUrl": "https://dev-webhook.nevua.markets/webhook"
      }
    }
  ]
}

```

**Event Closed - single market**

```json theme={null}
{
  "type": "event_status_notification",
  "eventStatusScope": "Event",
  "triggerType": "Closed",
  "userId": "68127a8ee0d25586bd0aeffd",
  "createdAt": "2025-09-30T12:48:14.109Z",
  "subscriptionId": "68132e17cff7571b55f629b5",
  "watchlistId": "68132e17cff7571b55f629b4",
  "watchlistName": "Bitcoin",
  "eventId": "40364",
  "eventTitle": "Bitcoin Up or Down - August 31, 6AM ET",
  "outcomes": "[\"Up\", \"Down\"]",
  "outcomePrices": "[\"1\", \"0\"]",
  "marketId": "583034",
  "marketQuestion": "Bitcoin Up or Down - August 31, 6AM ET"
  "polymarketSlug": "bitcoin-up-or-down-august-31-6am-et",
  "detectedAt": "2025-08-31T13:26:13.451Z",
  "detectedAtMs": 1756646773451,
  "channels": [
    {
      "type": "Webhook",
      "settings": {
        "webhookUrl": "https://dev-webhook.nevua.markets/webhook"
      }
    }
  ]
}
```

**Event Closed - multiple markets**

```json theme={null}
{
  "type": "event_status_notification",
  "eventStatusScope": "Event",
  "triggerType": "Closed",
  "userId": "685c205a15aa7e859743cbeb",
  "createdAt": "2025-09-30T12:48:14.109Z",
  "subscriptionId": "686fdfbbd20f44c15c33d93f",
  "watchlistId": "686fdfbbd20f44c15c33d93e",
  "watchlistName": "grok",
  "eventId": "30367",
  "eventTitle": "Which company has best AI model end of August?",
  "polymarketSlug": "which-company-has-best-ai-model-end-of-august",
  "detectedAt": "2025-08-31T20:12:04.976Z",
  "detectedAtMs": 1756671124976,
  "channels": [
    {
      "type": "Webhook",
      "settings": {
        "webhookUrl": "https://dev-webhook.nevua.markets/webhook"
      }
    }
  ]
}
```

\*\*

## Webhook Delivery

### HTTP Request Format

All webhook notifications are delivered as HTTP POST requests with the following characteristics:

* **Content-Type**: `application/json`
* **User-Agent**: `NevuaMarkets-Webhook/1.0`
* **Body**: JSON payload matching one of the schemas above

### Response Requirements

Your webhook endpoint should:

* Respond with a 2xx HTTP status code to indicate successful receipt
* Respond within 5 seconds to avoid timeout
* Handle duplicate notifications gracefully (notifications may be retried)

### Retry Policy

Failed webhook deliveries will be retried 2 times:

* Retry delay: 1 second
* Maximum retries: 2 retries, 3 attempts in total including the first.

### Security Considerations

* Use HTTPS endpoints for webhook URLs
* Implement signature verification if needed (contact support for details)
* Validate the notification structure before processing
* Consider implementing idempotency based on `subscriptionId` + `detectedAtMs`

## Troubleshooting

### Common Issues

1. **Missing notifications**: Check that your webhook URL is accessible and responding with 2xx status codes
2. **Duplicate notifications**: Implement idempotency handling based on notification IDs
3. **Timeout errors**: Ensure your webhook endpoint responds within 30 seconds

### Testing Your Webhook

You can test your webhook endpoint by creating a test subscription and triggering conditions manually, or by using tools like ngrok for local development.
