---
title: "Create webhook"
canonical_url: https://docs.zvid.io/docs/endpoints/create-webhook/
source: docs/endpoints/create-webhook.api.mdx
content_revision: 6338386a1dd87e4a
---

# Create webhook

`POST /api/webhooks`

Register an account endpoint. Registered deliveries are signed with HMAC-SHA256(secret, timestamp + "." + raw body). There are at most 5 total attempts (initial plus retries after 30, 60, 120 and 240 seconds), a 10-second HTTP timeout, and no redirect following. Endpoints are disabled after 20 consecutive exhausted deliveries. Creation and GET by ID return the signing secret.

## Authentication

- Option 1: `x-api-key: YOUR_API_KEY` (header). API key for authentication. Create one in your dashboard.
- Option 2: `Authorization: Bearer YOUR_ACCESS_TOKEN`. Dashboard JWT in Authorization: Bearer &lt;token>, only on operations that explicitly list this scheme. Prefer x-api-key for REST integrations. OAuth for hosted MCP is a separate connection at https://mcp.zvid.io/mcp.

Create API keys at [app.zvid.io/api-keys](https://app.zvid.io/api-keys). Keep credentials on your server.

## Parameters

This operation has no path, query, or additional header parameters.

## Request

The shell examples read credentials from `ZVID_API_KEY` (or `ZVID_ACCESS_TOKEN` for Bearer authentication). Set that variable in your environment. Replace sample project, template, job, and asset identifiers with values from your own account.

A request body is required.


### application/json

Unknown properties are rejected. Required properties: `url`.

| Field | Type | Required | Description and constraints |
| --- | --- | --- | --- |
| `body.url` | string | Yes | Maximum length: `2048`. Format: `uri`. |
| `body.description` | string | No | Maximum length: `255`. |
| `body.events` | array of `"render.completed"` / `"render.failed"` | No | Minimum items: `1`. Items must be unique. |

**Nested field: `body.events`**

Minimum items: `1`. Items must be unique.

**Array item: `body.events[]`**

Type: `"render.completed"` / `"render.failed"`.


### Request example: endpoint


```bash
curl --request POST 'https://api.zvid.io/api/webhooks' \
  --header "x-api-key: $ZVID_API_KEY" \
  --header 'Content-Type: application/json' \
  --data '{
  "url": "https://example.com/hooks/zvid",
  "events": [
    "render.completed",
    "render.failed"
  ]
}'
```

## Responses


### HTTP 201

Webhook created (includes secret)

Content type: `application/json`.

Required properties: `id`, `url`, `events`, `status`.

| Field | Type | Required | Description and constraints |
| --- | --- | --- | --- |
| `response.id` | string | Yes |  |
| `response.url` | string | Yes |  |
| `response.description` | string | No |  |
| `response.events` | array of `"render.completed"` / `"render.failed"` | Yes |  |
| `response.status` | `"active"` / `"disabled"` | Yes |  |
| `response.secret` | string | No | Returned by creation and single-webhook lookup; omitted from list/update responses. |
| `response.consecutiveFailures` | integer | No |  |
| `response.lastSuccessAt` | string OR null | No | At least one listed alternative must match. |
| `response.lastFailureAt` | string OR null | No | At least one listed alternative must match. |
| `response.lastFailureReason` | string OR null | No | At least one listed alternative must match. |
| `response.createdAt` | string | No |  |
| `response.updatedAt` | string | No |  |

**Nested field: `response.events`**

**Array item: `response.events[]`**

Type: `"render.completed"` / `"render.failed"`.

**Nested field: `response.lastSuccessAt`**

At least one listed alternative must match.

**anyOf alternative 1**

Type: string.

**anyOf alternative 2**

Type: null.

**Nested field: `response.lastFailureAt`**

At least one listed alternative must match.

**anyOf alternative 1**

Type: string.

**anyOf alternative 2**

Type: null.

**Nested field: `response.lastFailureReason`**

At least one listed alternative must match.

**anyOf alternative 1**

Type: string.

**anyOf alternative 2**

Type: null.


**Representative successful response response**

```json
{
  "id": "whk_abcdefghijklmnopqrst",
  "url": "https://example.com/hooks/zvid",
  "events": [
    "render.completed"
  ],
  "status": "active",
  "secret": "whsec_example_not_a_real_secret",
  "created": true
}
```

### HTTP 400

Invalid URL (the hosted API requires a public HTTPS address and rejects private hosts)

Content type: `application/json`.

Required properties: `error`.

| Field | Type | Required | Description and constraints |
| --- | --- | --- | --- |
| `response.error` | string | Yes |  |
| `response.message` | string | No |  |
| `response.details` | array of object | No |  |
| `response.planLimits` | object | No | Present on render validation errors; contains the authenticated user's current render limits. |

**Nested field: `response.details`**

**Array item: `response.details[]`**

Unknown properties are rejected. Required properties: `field`, `message`.

| Field | Type | Required | Description and constraints |
| --- | --- | --- | --- |
| `response.details[].field` | string | Yes |  |
| `response.details[].message` | string | Yes |  |


### HTTP 401

Unauthorized

Content type: `application/json`.

Unknown properties are rejected. Required properties: `error`.

| Field | Type | Required | Description and constraints |
| --- | --- | --- | --- |
| `response.error` | string | Yes | Error type |
| `response.message` | string | No | Human-readable error message |


## Schema definitions

The following definitions describe the fields referenced above. Expand a definition to inspect its complete contract.


### schema webhook request

**WebhookRequest**


Unknown properties are rejected. Required properties: `url`.

| Field | Type | Required | Description and constraints |
| --- | --- | --- | --- |
| `WebhookRequest.url` | string | Yes | Maximum length: `2048`. Format: `uri`. |
| `WebhookRequest.description` | string | No | Maximum length: `255`. |
| `WebhookRequest.events` | array of `"render.completed"` / `"render.failed"` | No | Minimum items: `1`. Items must be unique. |

**Nested field: `WebhookRequest.events`**

Minimum items: `1`. Items must be unique.

**Array item: `WebhookRequest.events[]`**

Type: `"render.completed"` / `"render.failed"`.


### schema webhook

**Webhook**


Required properties: `id`, `url`, `events`, `status`.

| Field | Type | Required | Description and constraints |
| --- | --- | --- | --- |
| `Webhook.id` | string | Yes |  |
| `Webhook.url` | string | Yes |  |
| `Webhook.description` | string | No |  |
| `Webhook.events` | array of `"render.completed"` / `"render.failed"` | Yes |  |
| `Webhook.status` | `"active"` / `"disabled"` | Yes |  |
| `Webhook.secret` | string | No | Returned by creation and single-webhook lookup; omitted from list/update responses. |
| `Webhook.consecutiveFailures` | integer | No |  |
| `Webhook.lastSuccessAt` | string OR null | No | At least one listed alternative must match. |
| `Webhook.lastFailureAt` | string OR null | No | At least one listed alternative must match. |
| `Webhook.lastFailureReason` | string OR null | No | At least one listed alternative must match. |
| `Webhook.createdAt` | string | No |  |
| `Webhook.updatedAt` | string | No |  |

**Nested field: `Webhook.events`**

**Array item: `Webhook.events[]`**

Type: `"render.completed"` / `"render.failed"`.

**Nested field: `Webhook.lastSuccessAt`**

At least one listed alternative must match.

**anyOf alternative 1**

Type: string.

**anyOf alternative 2**

Type: null.

**Nested field: `Webhook.lastFailureAt`**

At least one listed alternative must match.

**anyOf alternative 1**

Type: string.

**anyOf alternative 2**

Type: null.

**Nested field: `Webhook.lastFailureReason`**

At least one listed alternative must match.

**anyOf alternative 1**

Type: string.

**anyOf alternative 2**

Type: null.


### schema validation error

**ValidationError**


Required properties: `error`.

| Field | Type | Required | Description and constraints |
| --- | --- | --- | --- |
| `ValidationError.error` | string | Yes |  |
| `ValidationError.message` | string | No |  |
| `ValidationError.details` | array of object | No |  |
| `ValidationError.planLimits` | object | No | Present on render validation errors; contains the authenticated user's current render limits. |

**Nested field: `ValidationError.details`**

**Array item: `ValidationError.details[]`**

Unknown properties are rejected. Required properties: `field`, `message`.

| Field | Type | Required | Description and constraints |
| --- | --- | --- | --- |
| `ValidationError.details[].field` | string | Yes |  |
| `ValidationError.details[].message` | string | Yes |  |


### schema authentication error

**AuthenticationError**


Unknown properties are rejected. Required properties: `error`.

| Field | Type | Required | Description and constraints |
| --- | --- | --- | --- |
| `AuthenticationError.error` | string | Yes | Error type |
| `AuthenticationError.message` | string | No | Human-readable error message |


## Related resources

- [OpenAPI specification](https://docs.zvid.io/openapi.yaml)
- [Project payload schema](https://docs.zvid.io/schemas/render-payload.schema.json)
- [Quick Start](https://docs.zvid.io/docs/quick-start/)
- [Authentication guide](https://docs.zvid.io/docs/authentication/)
