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

# Webhooks on system state changes

## Webhook types

A webhook is a real-time callback that sends an HTTP POST request to your server-side app when a defined event happens in our Video Streaming service.
This way, you instantly receive updates and can trigger automated actions without manual checks by constant pulling API.

A single universal endpoint is used for all types of webhooks.

```json theme={null}
{
  "type": "stream|video|video_delete|restream",
  "message": { ... } 
}
```

Supported entities:

1. Live streams – `type: stream`
2. VOD videos:
   * on state change – `type: video`
   * on delete – `type: video_delete`
3. Restreamings – `type: restream`

The webhook will contain main fields of the entity for which the event occurred. This allows you to not pull the API to get additional data each time.

## Webhooks for Live

When the state of a live stream changes, the system triggers a webhook with type `stream`. The payload contains a message.stream object with stream properties.

**Behavior:**

* A webhook is fired on key state changes, such as ingest start, transcoding start, or stream stop.
* The payload allows you to track whether a stream is active, whether playback output is ready, its source, and related metadata.
* Both PUSH and PULL origins are supported.

**Live stream lifecycle:**

For live streams, `type: stream` webhooks can be sent at different stages of the stream lifecycle:

| Stage                 | live/backup\_live | transcoding | recording | Description                                                                                                 |
| --------------------- | ----------------- | ----------- | --------- | ----------------------------------------------------------------------------------------------------------- |
| Primary ingest starts | `true`            | `false`     | `false`   | Primary source connects; ingest is active, but playback might still be preparing, users will see 404 still. |
| Transcoding starts    | `true`            | `true`      | `false`   | Playback output is ready with status 200 OK; use this stage to show or activate a player for users.         |
| Recording starts      | `true`            | `true`      | `true`    | The live stream is being recorded.                                                                          |
| Stream stops          | `false`           | `false`     | `false`   | Final stage: the stream source disconnects or the broadcast ends, so the stream is not active.              |

<Info>
  Use `live: true` (or `backup_live: true`) to track active ingest. Use `transcoding: true` to track when the live stream is ready for playback.

  Read more in the article [Ingest & Backup](/streaming/live-streaming/primary-backup#stream-availability).
</Info>

**Fields:**

| Field                    | Type   | Description                                                                        |
| ------------------------ | ------ | ---------------------------------------------------------------------------------- |
| **id**                   | int    | Unique identifier of the stream                                                    |
| **live**                 | bool   | `true` if the stream is currently active, `false` if it has stopped                |
| **backup\_live**         | bool   | `true` if the backup source is currently active                                    |
| **recording**            | bool   | `true` if the stream is being recorded                                             |
| **transcoding**          | bool   | `true` if transcoding has started and playback output is ready, `false` by default |
| **client\_user\_id**     | string | Optional client-defined user ID, `null` if not provided                            |
| **client\_entity\_data** | string | Optional client metadata associated with the stream, `null` if not provided        |
| **pull**                 | bool   | `true` if the stream is pulled from an external origin, `false` if pushed          |
| **uri**                  | string | The source URI of the stream:                                                      |
| **stream\_source\_type** | string | Type of the stream source: `rtmp`, `srt`, `webrtc`, `https`                        |

**Example:**

Stream is ready for playback:

```json theme={null}
{
  "type": "stream",
  "message": {
    "stream": {
      "id": 1001,
      "live": true,
      "backup_live": false,
      "recording": false,
      "client_user_id": 10000001,
      "client_entity_data": "{ 'seq_id': '1234567890', 'name': 'John Doe', 'iat': 1516239022 }",
      "pull": false,
      "uri": "srt://vp-push-ed1-srt.gvideo.co:5001?streamid=12345#aaabbbcccddd",
      "stream_source_type": "srt",
      "transcoding": true
    }
  }
}
```

Stopped stream:

```json theme={null}
{
  "type": "stream",
  "message": {
    "stream": {
      "id": 1002,
      "live": false,
      "backup_live": false,
      "recording": false,
      "client_user_id": 10000001,
      "client_entity_data": "{ 'seq_id': '1234567890', 'name': 'John Doe', 'iat': 1516239022 }",
      "pull": true,
      "uri": "https://.../master.m3u8",
      "stream_source_type": "https",
      "transcoding": false
    }
  }
}
```

## Webhooks for VOD

VOD webhooks use `type: video` for create and status updates, and `type: video_delete` when a video is deleted.

| Webhook type   | Status               | Description                                                                                              |
| -------------- | -------------------- | -------------------------------------------------------------------------------------------------------- |
| `video`        | `empty`              | Video entity is created, but the source file is still being received.                                    |
| `video`        | `pending`            | Source file has been received and is being transcoded.                                                   |
| `video`        | `viewable`           | Playback is already available (not all qualities and codecs are ready, so transcoding is still ongoing). |
| `video`        | `ready`              | All qualities and codecs are processed and available for playback.                                       |
| `video`        | `error`              | Upload or processing failed; check the `error` field.                                                    |
| `video_delete` | Current video status | Video entity was deleted.                                                                                |

Read more about VOD statuses in [Video Lifecycle and Statuses](/streaming/video-hosting/vod-status).

### VOD create and update

A webhook with type `video` fires when a VOD file is created, processed, or becomes playable. Use the payload to track processing progress and available renditions.

**Behavior:**

* Sent on key status changes of a video: empty → pending → viewable → ready or error.
* converted\_videos\[].status reflects per-rendition progress like processing or complete.

**Fields:**

| Field                 | Type        | Description                                                                      |
| --------------------- | ----------- | -------------------------------------------------------------------------------- |
| **id**                | int         | VideoID                                                                          |
| **slug**              | string      | Public identifier used in playback URLs                                          |
| **name**              | string      | Video name                                                                       |
| **duration**          | int         | Duration of the video in milliseconds                                            |
| **stream\_id**        | int \| null | StreamID if it was recorded from a Live stream, otherwise `null`                 |
| **status**            | string      | Processing status of the video: `empty`, `pending`, `viewable`, `ready`, `error` |
| **converted\_videos** | array       | List of transcoded renditions with details                                       |
| └─ **name**           | string      | Rendition label (e.g., `vod1080p`)                                               |
| └─ **status**         | string      | Rendition status                                                                 |
| └─ **mp4\_url**       | string      | Direct URL for a rendition in MP4 fromat                                         |

See the statuses of VOD processing in API docs:

* Video status processing – [status](/api-reference/streaming/videos/get-video#response-status)
* Rendition status processing – [converted\_videos/status](/api-reference/streaming/videos/get-video#response-converted-videos)

**Example:**

Video uploaded:

```json theme={null}
{
  "type": "video",
  "message": {
    "video": {
      "id": 2001,
      "slug": "bJkptcIp9a5wrowz",
      "name": "football_videoplayback_720",
      "duration": 43989,
      "stream_id": null,
      "status": "empty",
      "converted_videos": []
    }
  }
}
```

Video becomes viewable (not all renditions are ready yet, but video can be watched by end-users already):

```json theme={null}
{
  "type": "video",
  "message": {
    "video": {
      "id": 2001,
      "slug": "bJkptcIp9a5wrowz",
      "name": "football_videoplayback_720",
      "duration": 43989,
      "stream_id": null,
      "status": "viewable",
      "converted_videos": [
        {
          "name": "4029_h264_720p",
          "status": "complete",
          "mp4_url": "https://102748.gvideo.io/videos/102748_bJkptcIp9a5wrowz/qid4029v1_h264_2700_720.mp4"
        },
        {
          "name": "4014_hevc_720p",
          "status": "processing",
          "mp4_url": "https://102748.gvideo.io/videos/102748_bJkptcIp9a5wrowz/qid4014v1_hevc_1620_720.mp4"
        },
        {
          "name": "3999_av1_720p",
          "status": "processing",
          "mp4_url": "https://102748.gvideo.io/videos/102748_bJkptcIp9a5wrowz/qid3999v1_av1_1350_720.mp4"
        }
      ]
    }
  }
}
```

### VOD delete

A webhook with type `video_delete` notify your system that a VOD entity was deleted so you can purge caches, revoke URLs, and clean metadata.

**Behavior:**

* Fired when a video is deleted via API or UI.
* Emitted once per deletion event.

**Fields:**

| Field           | Type      | Description                                                             |
| --------------- | --------- | ----------------------------------------------------------------------- |
| **id**          | integer   | VideoID                                                                 |
| **slug**        | string    | Public identifier used in playback URLs                                 |
| **name**        | string    | Video name                                                              |
| **status**      | string    | Processing status of the video                                          |
| **deleted\_at** | timestamp | ISO-8601 UTC timestamp of when the deletion was committed in the system |

**Example:**

```json theme={null}
{
  "type": "video_delete",
  "message": {
    "video": {
      "id": 2001,
      "slug": "bJkptcIp9a5wrowz",
      "name": "football_videoplayback_720",
      "status": "ready",
      "deleted_at": "2025-09-16T13:50:42.000Z"
    }
  }
}
```

## Webhooks for Restream

When a restream changes state (for example, starts or stops), the system sends a webhook with type `restream`.
The payload contains a message.restream object.

| Stage           | live    | Description                                                                         |
| --------------- | ------- | ----------------------------------------------------------------------------------- |
| Restream starts | `true`  | Restream is active and sends the source live stream to the destination.             |
| Restream stops  | `false` | Final stage: restream is not active and no longer sends content to the destination. |

**Behavior:**

* Fired whenever a restream goes live or stops.
* Allows you to track the status of a specific restream linked to a live stream.

**Fields:**

| Field          | Type   | Description                                                        |
| -------------- | ------ | ------------------------------------------------------------------ |
| **id**         | int    | Unique identifier of the restream.                                 |
| **name**       | string | Human-readable name of the restream.                               |
| **stream\_id** | int    | ID of the source live stream that this restream is linked to.      |
| **live**       | bool   | `true` if the restream is currently active, `false` if it stopped. |

**Example:**

Restream starts:

```json theme={null}
{
  "type": "restream",
  "message": {
    "restream": {
      "id": 3001,
      "name": "RTMP from Brodcast#1 to Youtube",
      "stream_id": 1001,
      "live": true
    }
  }
}
```

Restream stops:

```json theme={null}
{
  "type": "restream",
  "message": {
    "restream": {
      "id": 3001,
      "name": "RTMP from Brodcast#1 to Youtube",
      "stream_id": 1001,
      "live": false
    }
  }
}
```

## Sending events

We deliver webhooks from IP addresses `92.223.112.0/24` and `92.223.123.0/24`. So put them into the whitelist.

Events are sent only once. If your server is unavailable, undelivered webhooks won't be sent again.

## How to enable webhooks

<Info>
  At the moment, webhooks can only be set up with our help. Tell us your end-point and we will install it in your account.
</Info>

1\. Prepare your HTTP server to receive webhooks.

2\. Contact us via chat or email [support@gcore.com](mailto:support@gcore.com) and ask to enable the webhook integration. Specify your ID (personal client ID) and the URL of the server that will receive webhooks. You can find your ID in the [Gcore Customer Portal](https://portal.gcore.com/accounts/reports/dashboard).

<Frame>
  <img src="https://mintcdn.com/gcore/J8Ql0Xb4rcGyS5tD/images/docs/streaming-platform/extra-features/get-webhooks-from-the-streaming-platform/image.png?fit=max&auto=format&n=J8Ql0Xb4rcGyS5tD&q=85&s=e2f7879eaf96577631e01bbe3276230a" alt="your ID in the Gcore Customer Portal" width="6814" height="1071" data-path="images/docs/streaming-platform/extra-features/get-webhooks-from-the-streaming-platform/image.png" />
</Frame>

The message template: *"Good afternoon! Please configure the Video Streaming webhook integration for my account with ID..... The URL of my server to send webhooks to is ...."*.

3\. We will notify you when we configure the webhook integration.

<Note>
  **Testing:**

  Also you can easily create and inspect webhook requests using web site [https://webhook.site](https://webhook.site).
  For example, the temporary link look like `https://webhook.site/56ce9331-4ec4-4fa1-bf23-4c4e14276f24` to capture and display incoming webhook payloads for debugging. Create your own and send it to us to set up.
</Note>
