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

# Webhooks

> Receive listing and tweet events from watches.

Create a watch with `POST /v1/{source}/watches` and provide a `webhook_url`. When matches change, Nephia POSTs an event payload to your endpoint.

<h2 id="event-types">
  Event types
</h2>

| `type`                  | Source | Description                              |
| ----------------------- | ------ | ---------------------------------------- |
| `listing.created`       | Vinted | New listing matched the watch criteria   |
| `listing.price_changed` | Vinted | Price changed on a tracked listing       |
| `listing.delisted`      | Vinted | Listing removed or no longer matches     |
| `tweet.created`         | X      | New tweet matched the watch search query |

## Payload envelope

Every event uses the same shape. Unused fields are `null`.

```json theme={null}
{
  "id": "event-uuid",
  "type": "listing.price_changed",
  "watchId": "watch-uuid",
  "listing": { "...": "canonical listing object" },
  "tweet": null,
  "previousPrice": 45.0,
  "occurredAt": "2026-07-07T12:00:00.000Z"
}
```

### Vinted `listing.price_changed`

```json theme={null}
{
  "id": "evt_01k2abc",
  "type": "listing.price_changed",
  "watchId": "watch_01k2xyz",
  "listing": {
    "id": "41234567",
    "source": "vinted",
    "market": "fr",
    "title": "Nike Air Max 90",
    "price": 42.0,
    "currency": "EUR"
  },
  "tweet": null,
  "previousPrice": 45.0,
  "occurredAt": "2026-07-07T12:00:00.000Z"
}
```

### X `tweet.created`

```json theme={null}
{
  "id": "evt_01k2def",
  "type": "tweet.created",
  "watchId": "watch_01k2uvw",
  "listing": null,
  "tweet": {
    "id": "1890123456789012345",
    "text": "Just shipped the new release.",
    "authorId": "44196397",
    "createdAt": "2026-07-07T12:00:00.000Z"
  },
  "previousPrice": null,
  "occurredAt": "2026-07-07T12:00:00.000Z"
}
```

## Signature verification

Each delivery includes an `X-Signature` header: HMAC-SHA256 of the raw JSON body using your webhook signing secret.

```typescript theme={null}
import { createHmac, timingSafeEqual } from 'node:crypto';

function verifySignature(body: string, signature: string, secret: string): boolean {
  const expected = createHmac('sha256', secret).update(body).digest('hex');
  return timingSafeEqual(Buffer.from(signature), Buffer.from(expected));
}
```

## Retries

Failed deliveries (non-2xx or network error) retry with backoff: immediate, +30s, +120s (3 attempts total).

## Replay events

Fetch historical events for a watch (free):

```bash theme={null}
curl "https://api.nephia.cc/v1/vinted/watches/WATCH_ID/events?since=2026-07-01T00:00:00.000Z" \
  -H "x-api-key: YOUR_API_KEY"
```

```bash theme={null}
curl "https://api.nephia.cc/v1/x/watches/WATCH_ID/events?since=2026-07-01T00:00:00.000Z" \
  -H "x-api-key: YOUR_API_KEY"
```
