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

# Webhook payloads

> The envelope, headers, and payload of every webhook event type, with an example of each.

Every webhook delivery is one JSON object, sent as the body of one `POST` request. This page describes the envelope and each event type. To register an endpoint, verify signatures, and handle retries, see [Webhooks](/guides/rest/webhooks.md).

The trade and feed examples tell one story. Event `101` opens a Bitcoin long on source message `tg:1001:42`. A few minutes later the event is corrected: Centaur deletes `101` and creates `102` with the corrected price. Later, the only event of message `tg:1001:57` is removed.

## Envelope

| Field | Type | Meaning |
| - | - | - |
| `id` | string | Unique event ID (a UUID, version 7). Deduplicate on it: a retry or a replay repeats the same `id`. Treat it as an opaque string. |
| `type` | string | The event type, for example `trade_event.created`. |
| `occurredAt` | string | When the change was recorded in Centaur's data, in ISO-8601 UTC. For positioning events, when the view was recalculated; for a test delivery, when you requested it. Centaur detects a change some time after it is recorded. |
| `sequence` | integer | A counter per endpoint. It starts at `1` and increases with each delivery Centaur starts sending to your endpoint. A retry keeps its number; a replay gets a new one. |
| `schemaVersion` | integer | The payload schema version. Currently `1`. |
| `data` | object | The payload. Its shape depends on `type`, as described below. |

Each request also carries these headers:

| Header | Value |
| - | - |
| `Content-Type` | `application/json` |
| `User-Agent` | `Centaur-Webhooks/1` |
| `Centaur-Event-Id` | The event `id` |
| `Centaur-Event-Type` | The event `type` |
| `Centaur-Sequence` | The delivery's `sequence` |
| `Centaur-Signature` | `t=<unix seconds>,v1=<hex>`, with a second `v1` during a secret rotation. See [Verify signatures](/guides/rest/webhooks.md#verify-signatures). |

Some fields are open sets: `origin` on trade events and `kind` on feed events. New values can appear without a schema version change. When you receive a value you do not know, inspect the event before acting on it.

Payloads can also gain fields without a schema version change, so ignore fields you do not know instead of rejecting the delivery. A new event type reaches only endpoints that subscribe to it, and `eventTypes` accepts only the types on this page.

## Trade events

A trade event payload is one row of [`GET /v2/events`](/guides/rest/data-reads#events), keyed by the event `id`. New trade events include `assetId` and the position `direction` (`long` or `short`), as REST does. Older stored events stay replayable and may omit them. Event rows never change, so there is no `trade_event.updated`: a corrected event is deleted and a new one created.

`trade_event.created` adds `origin`:

* `new`: the event is a first detection.
* `replacement`: another event of the same source message (the same `messageId`) was deleted at the same time. Use `messageId` to pair the `trade_event.deleted` with the `trade_event.created` that replaces it.

`origin` describes what Centaur observed, not why it happened. A `replacement` can carry the same content as the event it replaces: see [Limitations](/guides/rest/webhooks.md#limitations).

`trade_event.deleted` repeats the row as it was last delivered. Stop treating that event as true.

### trade\_event.created

```json theme={null}
{
  "id": "01a0e77a-0a10-79f4-94ae-460be7c2ff7f",
  "type": "trade_event.created",
  "occurredAt": "2026-09-28T10:05:30.000Z",
  "sequence": 3,
  "schemaVersion": 1,
  "data": {
    "id": 102,
    "type": "open",
    "direction": "long",
    "price": 64100,
    "quoteSymbol": "USDT",
    "timeOfEvent": "2026-09-28T10:00:00.000Z",
    "assumed": false,
    "retrospective": false,
    "autoGenerated": false,
    "positionId": 55,
    "traderId": 7,
    "assetId": 1,
    "messageId": "tg:1001:42",
    "origin": "replacement"
  }
}
```

### trade\_event.deleted

```json theme={null}
{
  "id": "01a0e77a-0a10-73de-a5c9-42b194b637a1",
  "type": "trade_event.deleted",
  "occurredAt": "2026-09-28T10:05:30.000Z",
  "sequence": 2,
  "schemaVersion": 1,
  "data": {
    "id": 101,
    "type": "open",
    "direction": "long",
    "price": 64000.5,
    "quoteSymbol": "USDT",
    "timeOfEvent": "2026-09-28T10:00:00.000Z",
    "assumed": false,
    "retrospective": false,
    "autoGenerated": false,
    "positionId": 55,
    "traderId": 7,
    "assetId": 1,
    "messageId": "tg:1001:42"
  }
}
```

## Feed items

A feed item payload is one source-message group of [`GET /v2/feed`](/guides/rest/feed), keyed by the Source Message ID (`data.id`), with the same source block, trader card and curation. Instead of a single `events` list it carries three lists:

* `current`: the message's active events after the change. Treat it as the truth for the message.
* `added`: events that became active in this change.
* `removed`: events that stopped being active in this change, with `id`, `kind`, `assetId` and `direction`. Legacy stored removals may omit asset and direction.

The verb comes from counting the message's active events before and after the change:

| Type | Before | After | `current` | `added` | `removed` |
| - | - | - | - | - | - |
| `feed_item.created` | none | some | not empty | the same events as `current` | empty |
| `feed_item.updated` | some | some, changed | not empty | events that are now in `current` | events that are not in `current` |
| `feed_item.deleted` | some | none | empty | empty | not empty |

Centaur sends at most one feed item event per message per detection pass. The type says where the message stands afterwards; `added` and `removed` say what happened. `removed` means stop treating the event as true. It is not an instruction to reverse a trade.

Each feed event carries `kind`. Today every event is a `trade`; more kinds may follow. Feed event assets always include `slug`, which is `null` when unavailable.

### feed\_item.created

```json theme={null}
{
  "id": "01a0e775-7630-7ee6-a325-c2bc9d480d35",
  "type": "feed_item.created",
  "occurredAt": "2026-09-28T10:00:30.000Z",
  "sequence": 1,
  "schemaVersion": 1,
  "data": {
    "id": "tg:1001:42",
    "writtenAt": "2026-09-28T10:00:00.000Z",
    "source": {
      "platform": "TELEGRAM",
      "url": null,
      "text": "Long BTC here",
      "attachments": [],
      "identity": {
        "platform": "TELEGRAM",
        "sourceIdentityId": "tg:1001",
        "displayName": "Alpha Calls",
        "handle": "alphacalls",
        "avatarUrl": null,
        "profileUrl": "https://t.me/alphacalls",
        "audienceCount": 1200
      }
    },
    "trader": {
      "id": 7,
      "name": "Alpha",
      "slug": "alpha",
      "avatarUrl": null
    },
    "current": [
      {
        "id": 101,
        "type": "open",
        "price": 64000.5,
        "quoteSymbol": "USDT",
        "timeOfEvent": "2026-09-28T10:00:00.000Z",
        "direction": "long",
        "assumed": false,
        "retrospective": false,
        "positionId": 55,
        "traderId": 7,
        "assetId": 1,
        "asset": {
          "id": 1,
          "name": "Bitcoin",
          "symbol": "BTC",
          "slug": "crypto-btc",
          "logoUrl": null
        },
        "kind": "trade"
      }
    ],
    "added": [
      {
        "id": 101,
        "type": "open",
        "price": 64000.5,
        "quoteSymbol": "USDT",
        "timeOfEvent": "2026-09-28T10:00:00.000Z",
        "direction": "long",
        "assumed": false,
        "retrospective": false,
        "positionId": 55,
        "traderId": 7,
        "assetId": 1,
        "asset": {
          "id": 1,
          "name": "Bitcoin",
          "symbol": "BTC",
          "slug": "crypto-btc",
          "logoUrl": null
        },
        "kind": "trade"
      }
    ],
    "removed": []
  }
}
```

### feed\_item.updated

```json theme={null}
{
  "id": "01a0e77a-0a10-79cb-973a-c987d08a640d",
  "type": "feed_item.updated",
  "occurredAt": "2026-09-28T10:05:30.000Z",
  "sequence": 4,
  "schemaVersion": 1,
  "data": {
    "id": "tg:1001:42",
    "writtenAt": "2026-09-28T10:00:00.000Z",
    "source": {
      "platform": "TELEGRAM",
      "url": null,
      "text": "Long BTC here",
      "attachments": [],
      "identity": {
        "platform": "TELEGRAM",
        "sourceIdentityId": "tg:1001",
        "displayName": "Alpha Calls",
        "handle": "alphacalls",
        "avatarUrl": null,
        "profileUrl": "https://t.me/alphacalls",
        "audienceCount": 1200
      }
    },
    "trader": {
      "id": 7,
      "name": "Alpha",
      "slug": "alpha",
      "avatarUrl": null
    },
    "current": [
      {
        "id": 102,
        "type": "open",
        "price": 64100,
        "quoteSymbol": "USDT",
        "timeOfEvent": "2026-09-28T10:00:00.000Z",
        "direction": "long",
        "assumed": false,
        "retrospective": false,
        "positionId": 55,
        "traderId": 7,
        "assetId": 1,
        "asset": {
          "id": 1,
          "name": "Bitcoin",
          "symbol": "BTC",
          "slug": "crypto-btc",
          "logoUrl": null
        },
        "kind": "trade"
      }
    ],
    "added": [
      {
        "id": 102,
        "type": "open",
        "price": 64100,
        "quoteSymbol": "USDT",
        "timeOfEvent": "2026-09-28T10:00:00.000Z",
        "direction": "long",
        "assumed": false,
        "retrospective": false,
        "positionId": 55,
        "traderId": 7,
        "assetId": 1,
        "asset": {
          "id": 1,
          "name": "Bitcoin",
          "symbol": "BTC",
          "slug": "crypto-btc",
          "logoUrl": null
        },
        "kind": "trade"
      }
    ],
    "removed": [
      {
        "id": 101,
        "kind": "trade",
        "assetId": 1,
        "direction": "long"
      }
    ]
  }
}
```

### feed\_item.deleted

```json theme={null}
{
  "id": "01a0e851-3030-7b3f-a3e1-fd9829699c8d",
  "type": "feed_item.deleted",
  "occurredAt": "2026-09-28T14:00:30.000Z",
  "sequence": 5,
  "schemaVersion": 1,
  "data": {
    "id": "tg:1001:57",
    "writtenAt": "2026-09-28T13:40:00.000Z",
    "source": {
      "platform": "TELEGRAM",
      "url": null,
      "text": "Short ETH",
      "attachments": [],
      "identity": {
        "platform": "TELEGRAM",
        "sourceIdentityId": "tg:1001",
        "displayName": "Alpha Calls",
        "handle": "alphacalls",
        "avatarUrl": null,
        "profileUrl": "https://t.me/alphacalls",
        "audienceCount": 1200
      }
    },
    "trader": {
      "id": 7,
      "name": "Alpha",
      "slug": "alpha",
      "avatarUrl": null
    },
    "current": [],
    "added": [],
    "removed": [
      {
        "id": 104,
        "kind": "trade",
        "assetId": 1,
        "direction": "long"
      }
    ]
  }
}
```

## Positioning

A positioning event carries one whole [Position Intelligence](/guides/rest/signal-intelligence.md) view after Centaur recalculated it. It is sent when top-10 membership changes, or a retained top-10 asset changes category in Crowd Fade or Smart Money. Crossing the #10 boundary counts as entering or leaving; rank movement within the top 10 and changes wholly outside it send nothing. Leaders' Book evaluates the first 10 rows of each part independently. Each event carries the whole view, so its body is much larger than a trade or feed event.

| Type | View | REST path |
| - | - | - |
| `positioning.trending.updated` | Trending | `/v2/signals/trending` |
| `positioning.specialist_ideas.updated` | Specialist Ideas | `/v2/signals/specialist-ideas` |
| `positioning.early_opportunities.updated` | Early Opportunities | `/v2/signals/early-opportunities` |
| `positioning.crowd_fade.updated` | Crowd Fade | `/v2/signals/crowd-fade` |
| `positioning.smart_money.updated` | Smart Money vs Crowd | `/v2/signals/smart-money` |
| `positioning.leaders_book.updated` | Leaders' Book | `/v2/signals/leaders-book` |

The payload has two fields:

* `result`: the view exactly as its REST path returns it with default parameters, including `calculationAt` and the resolved `parameters`. Endpoint filters do not apply: the view is always complete.
* `changes`: what changed since the previous calculation of the same view.

Each entry in `changes` has a `kind` and a `key`. The key identifies a row the way the view does:

| View | Rows | `key` | Kinds |
| - | - | - | - |
| Trending, Specialist Ideas, Early Opportunities | one per asset and direction | `<assetId>:<direction>`, for example `1:long` | `entered`, `left` |
| Leaders' Book confluence (`part: confluence`) | one per asset and direction | `<assetId>:<direction>` | `entered`, `left` |
| Leaders' Book portfolios (`part: portfolios`) | one per trader | `<traderId>` | `entered`, `left` |
| Crowd Fade, Smart Money vs Crowd | one per asset | `<assetId>` | `entered` with `to`, `left` with `from`, `category_changed` with `from` and `to` |

`from` and `to` are directions (`long` or `short`): the crowded side for Crowd Fade, and the smart cohort's direction for Smart Money vs Crowd. In views with one row per asset and direction, a direction flip is a `left` plus an `entered`. Each calculation is compared with the previous one, with no smoothing, so a row near a threshold can enter and leave on consecutive calculations.

### positioning.trending.updated

```json theme={null}
{
  "id": "01a0ed09-3a00-7a83-9c22-c0b67fb5612c",
  "type": "positioning.trending.updated",
  "occurredAt": "2026-09-29T12:00:00.000Z",
  "sequence": 6,
  "schemaVersion": 1,
  "data": {
    "result": {
      "calculationAt": "2026-09-29T12:00:00.000Z",
      "coverage": {
        "requestedAssets": 2,
        "availableAssets": 2,
        "insufficientHistoryAssets": 0,
        "missingAssets": 0,
        "failedAssets": 0
      },
      "parameters": {
        "windowDays": 7,
        "limit": 50
      },
      "results": [
        {
          "assetId": 1,
          "direction": "long",
          "traderCount": 9,
          "positionCount": 11,
          "pricedEntries": 11,
          "averageEntry": 62850.25,
          "currentPrice": 65000,
          "currentQuoteAt": "2026-09-29T11:59:30.000Z",
          "priceStatus": "available",
          "openReturnPercent": 3.42,
          "countBefore": 5,
          "netNow": 6,
          "netBefore": 2,
          "delta": 4
        },
        {
          "assetId": 2,
          "direction": "short",
          "traderCount": 4,
          "positionCount": 4,
          "pricedEntries": 4,
          "averageEntry": 2650,
          "currentPrice": 2580,
          "currentQuoteAt": "2026-09-29T11:59:30.000Z",
          "priceStatus": "available",
          "openReturnPercent": 2.64,
          "countBefore": 2,
          "netNow": 1,
          "netBefore": -2,
          "delta": 3
        }
      ]
    },
    "changes": [
      {
        "kind": "entered",
        "key": "2:short"
      },
      {
        "kind": "left",
        "key": "3:long"
      }
    ]
  }
}
```

### positioning.specialist\_ideas.updated

```json theme={null}
{
  "id": "01a0ed09-3a00-7983-90fc-5c47a3eb5efc",
  "type": "positioning.specialist_ideas.updated",
  "occurredAt": "2026-09-29T12:00:00.000Z",
  "sequence": 7,
  "schemaVersion": 1,
  "data": {
    "result": {
      "calculationAt": "2026-09-29T12:00:00.000Z",
      "coverage": {
        "requestedAssets": 1,
        "availableAssets": 1,
        "insufficientHistoryAssets": 0,
        "missingAssets": 0,
        "failedAssets": 0
      },
      "parameters": {
        "limit": 50,
        "minEvaluations": 5,
        "minWinRatePercent": 60,
        "minSpecialists": 2,
        "sampleWindow": "YTD",
        "evaluationWindow": "30D"
      },
      "results": [
        {
          "assetId": 1,
          "direction": "long",
          "traderCount": 2,
          "positionCount": 2,
          "pricedEntries": 2,
          "averageEntry": 63500,
          "currentPrice": 65000,
          "currentQuoteAt": "2026-09-29T11:59:30.000Z",
          "priceStatus": "available",
          "openReturnPercent": 2.36,
          "specialists": [
            {
              "traderId": 7,
              "evaluatedCount": 12,
              "winRatePercent": 75
            },
            {
              "traderId": 9,
              "evaluatedCount": 8,
              "winRatePercent": 62.5
            }
          ]
        }
      ]
    },
    "changes": [
      {
        "kind": "entered",
        "key": "1:long"
      }
    ]
  }
}
```

### positioning.early\_opportunities.updated

```json theme={null}
{
  "id": "01a0ed09-3a00-768c-80c8-5630b4a04998",
  "type": "positioning.early_opportunities.updated",
  "occurredAt": "2026-09-29T12:00:00.000Z",
  "sequence": 8,
  "schemaVersion": 1,
  "data": {
    "result": {
      "calculationAt": "2026-09-29T12:00:00.000Z",
      "parameters": {
        "windowDays": 7,
        "minTraders": 2,
        "maxTraders": 3,
        "movementThresholdPercent": 10,
        "limit": 50
      },
      "historicalRequestedAt": "2026-09-22T12:00:00.000Z",
      "coverage": {
        "latest": {
          "requestedAssets": 3,
          "availableAssets": 3,
          "insufficientHistoryAssets": 0,
          "missingAssets": 0,
          "failedAssets": 0
        },
        "historical": {
          "requestedAssets": 3,
          "availableAssets": 2,
          "insufficientHistoryAssets": 1,
          "missingAssets": 0,
          "failedAssets": 0
        }
      },
      "candidateGroups": 3,
      "missingPriceGroups": 1,
      "results": [
        {
          "assetId": 4,
          "direction": "long",
          "traderCount": 2,
          "positionCount": 2,
          "pricedEntries": 2,
          "averageEntry": 38.2,
          "currentPrice": 44.1,
          "currentQuoteAt": "2026-09-29T11:59:30.000Z",
          "priceStatus": "available",
          "openReturnPercent": 15.45,
          "historicalPrice": 39.5,
          "historicalQuoteAt": null,
          "movementPercent": 11.65
        }
      ]
    },
    "changes": [
      {
        "kind": "entered",
        "key": "4:long"
      }
    ]
  }
}
```

### positioning.crowd\_fade.updated

```json theme={null}
{
  "id": "01a0ed09-3a00-7caf-83f6-b178fe3de4bb",
  "type": "positioning.crowd_fade.updated",
  "occurredAt": "2026-09-29T12:00:00.000Z",
  "sequence": 9,
  "schemaVersion": 1,
  "data": {
    "result": {
      "calculationAt": "2026-09-29T12:00:00.000Z",
      "coverage": {
        "requestedAssets": 1,
        "availableAssets": 1,
        "insufficientHistoryAssets": 0,
        "missingAssets": 0,
        "failedAssets": 0
      },
      "parameters": {
        "minAbsNet": 7,
        "limit": 50
      },
      "candidateGroups": 1,
      "results": [
        {
          "assetId": 3,
          "direction": "long",
          "traderCount": 11,
          "positionCount": 12,
          "pricedEntries": 12,
          "averageEntry": 182.4,
          "currentPrice": 171.3,
          "currentQuoteAt": "2026-09-29T11:59:30.000Z",
          "priceStatus": "available",
          "openReturnPercent": -6.09,
          "net": 8,
          "fadeDirection": "short"
        }
      ]
    },
    "changes": [
      {
        "kind": "entered",
        "key": "3",
        "to": "long"
      }
    ]
  }
}
```

### positioning.smart\_money.updated

```json theme={null}
{
  "id": "01a0ed09-3a00-7226-8b93-cf5c86bba927",
  "type": "positioning.smart_money.updated",
  "occurredAt": "2026-09-29T12:00:00.000Z",
  "sequence": 10,
  "schemaVersion": 1,
  "data": {
    "result": {
      "calculationAt": "2026-09-29T12:00:00.000Z",
      "coverage": {
        "requestedAssets": 1,
        "availableAssets": 1,
        "insufficientHistoryAssets": 0,
        "missingAssets": 0,
        "failedAssets": 0
      },
      "parameters": {
        "limit": 50,
        "minEvaluations": 5,
        "minWinRatePercent": 60,
        "sampleWindow": "YTD",
        "evaluationWindow": "30D",
        "minLeaderEvaluations": 10,
        "leaderPercent": 20
      },
      "results": [
        {
          "assetId": 1,
          "gap": 75,
          "smart": {
            "direction": "long",
            "longs": 5,
            "shorts": 1,
            "net": 4,
            "eligibleCount": 6,
            "netPercent": 66.67,
            "averageEntry": 61200,
            "currentPrice": 65000,
            "currentQuoteAt": "2026-09-29T11:59:30.000Z",
            "priceStatus": "available",
            "openReturnPercent": 6.21
          },
          "crowd": {
            "direction": "short",
            "longs": 4,
            "shorts": 6,
            "net": -2,
            "eligibleCount": 24,
            "netPercent": -8.33,
            "averageEntry": 66100,
            "currentPrice": 65000,
            "currentQuoteAt": "2026-09-29T11:59:30.000Z",
            "priceStatus": "available",
            "openReturnPercent": 1.66
          }
        }
      ]
    },
    "changes": [
      {
        "kind": "category_changed",
        "key": "1",
        "from": "short",
        "to": "long"
      }
    ]
  }
}
```

### positioning.leaders\_book.updated

```json theme={null}
{
  "id": "01a0ed09-3a00-73bd-bfa4-b9e5f74d7097",
  "type": "positioning.leaders_book.updated",
  "occurredAt": "2026-09-29T12:00:00.000Z",
  "sequence": 11,
  "schemaVersion": 1,
  "data": {
    "result": {
      "calculationAt": "2026-09-29T12:00:00.000Z",
      "coverage": {
        "requestedAssets": 1,
        "availableAssets": 1,
        "insufficientHistoryAssets": 0,
        "missingAssets": 0,
        "failedAssets": 0
      },
      "parameters": {
        "sampleWindow": "YTD",
        "evaluationWindow": "30D",
        "minLeaderEvaluations": 0,
        "leaderCount": 30,
        "confluenceLimit": 10,
        "minConfluenceTraders": 2
      },
      "portfolios": [
        {
          "traderId": 7,
          "rank": 1,
          "medianReturnPercent": 4.85,
          "evaluatedCount": 12,
          "positions": [
            {
              "positionId": 55,
              "assetId": 1,
              "direction": "long",
              "openPrice": 64100,
              "openedAt": "2026-09-28T10:00:00.000Z",
              "currentPrice": 65000,
              "currentQuoteAt": "2026-09-29T11:59:30.000Z",
              "priceStatus": "available",
              "openReturnPercent": 1.4
            }
          ]
        },
        {
          "traderId": 9,
          "rank": 2,
          "medianReturnPercent": 3.1,
          "evaluatedCount": 8,
          "positions": [
            {
              "positionId": 61,
              "assetId": 1,
              "direction": "long",
              "openPrice": 63000,
              "openedAt": "2026-09-25T08:30:00.000Z",
              "currentPrice": 65000,
              "currentQuoteAt": "2026-09-29T11:59:30.000Z",
              "priceStatus": "available",
              "openReturnPercent": 3.17
            }
          ]
        }
      ],
      "confluence": [
        {
          "assetId": 1,
          "direction": "long",
          "traderCount": 2,
          "positionCount": 2,
          "pricedEntries": 2,
          "averageEntry": 63550,
          "currentPrice": 65000,
          "currentQuoteAt": "2026-09-29T11:59:30.000Z",
          "priceStatus": "available",
          "openReturnPercent": 2.28,
          "netCount": 2
        }
      ]
    },
    "changes": [
      {
        "part": "portfolios",
        "kind": "entered",
        "key": "9"
      },
      {
        "part": "confluence",
        "kind": "entered",
        "key": "1:long"
      }
    ]
  }
}
```


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.