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

# Payload format

The Standard Webhooks envelope, headers, and signature recipe.

# Webhook payload format

Motioness uses [Standard Webhooks](https://www.standardwebhooks.com/). One-line summary:

> POST your webhook_url with a JSON body, three headers (`webhook-id`, `webhook-timestamp`, `webhook-signature`), and an HMAC-SHA256 signature over `${id}.${ts}.${body}`.

## Body

```json
{
  "id": "evt_01HXY3K…",
  "type": "asset.completed",
  "ts": 1714801234567,
  "asset_id": "a25b330a71e2bc6b",
  "project_id": "proj_abc",
  "request_id": "req_xyz",
  "data": { /* event-specific */ }
}
```

| Field | Description |
|---|---|
| `id` | ULID-shaped event id. **Idempotency key** — retries reuse the same id. |
| `type` | Event type, namespaced (`asset.completed`, `asset.failed`, etc.) |
| `ts` | Unix milliseconds when the event was generated |
| `asset_id` | Content-addressed asset id (null for `asset.test`) |
| `project_id` | Project that owns the asset |
| `request_id` | Original request id from the prepare call |
| `data` | Event-type-specific payload — see [event types](/reference/event-types) |

## Headers

```text
content-type: application/json
webhook-id: evt_01HXY3K...
webhook-timestamp: 1714801234
webhook-signature: v1,base64-hmac
```

`webhook-signature` may carry multiple comma-or-space-separated `v1,...` entries during secret rotation. Verify any matches.

## Signature

```text
hmac_sha256(secret, `${webhook-id}.${webhook-timestamp}.${body}`)
```

Where `body` is the **exact** raw bytes you received (don't re-stringify after parsing — order/whitespace can change).

If the secret is prefixed `whsec_` (it usually is), strip the prefix and base64-decode the remainder before using as the HMAC key.

## Verify recipe

See [webhooks guide](/guides/webhooks#verify) for full Node + Python recipes.

## Replay-attack protection

Reject events older than 5 minutes:

```ts
if (Math.abs(Math.floor(Date.now() / 1000) - Number(ts)) > 300) {
  return res.status(401).end();
}
```

## Retry schedule

Failed deliveries (non-2xx, timeout > 10s) retry on `30s, 2m, 10m, 30m, 2h`. After 5 failed attempts the delivery is marked `dead`.

## Inspect / replay

```bash
# List recent deliveries
curl https://motioness.com/api/projects/$PROJECT_ID/webhooks/deliveries -b cookie.txt

# Inspect one
curl https://motioness.com/api/projects/$PROJECT_ID/webhooks/deliveries/$DELIVERY_ID -b cookie.txt

# Re-enqueue a dead delivery
curl -X POST https://motioness.com/api/projects/$PROJECT_ID/webhooks/deliveries/$DELIVERY_ID/redeliver -b cookie.txt
```