Live Events API
Managed live streaming and event broadcasting.
Events are created and run from the dashboard: stream keys, access tokens, the rehearsal → live → stop lifecycle, recordings, stats and health. The API below is the public viewer side, which resolves watch state for watch pages and embeds.
RTMP ingest: rtmp://ingest.wayscloud.services/live with the stream key from the dashboard.
Viewer endpoints (public, no authentication)
Resolve event watch state for watch pages, embeds, and custom players. Verify viewer access for password- or token-protected events.
The resolve endpoint returns two state fields:
watch_state— canonical viewer-facing UI state (not_started,access_required,live,replay_available, etc.)status— internal lifecycle state for diagnostics
Access control modes:
| Mode | Behavior |
|---|---|
public | Anyone with the URL can watch. Playback URLs returned directly. |
password | Viewer submits password → receives access grant + playback. |
token | Viewer submits pre-shared token → receives access grant. Token consumed on playback start, not on verify. |
tenant_only | Viewer must be authenticated as a member of the same customer account. |
Watch pages: https://live.wayscloud.services/watch/{slug}Embed: https://live.wayscloud.services/embed/{slug}
Manage events in dashboard: my.wayscloud.services/live-events
Endpoints
| Method | Path | Description |
|---|---|---|
GET | /v1/live-events/watch/{slug} | Resolve watch state |
POST | /v1/live-events/watch/{slug}/verify-password | Verify event password |
POST | /v1/live-events/watch/{slug}/verify-token | Verify watch token |
POST | /v1/live-events/watch/{slug}/consume-grant | Consume access grant on playback start |
GET | /v1/live-events/watch/by-id/{public_id} | Resolve watch state |
POST | /v1/live-events/watch/by-id/{public_id}/verify-password | Verify event password |
POST | /v1/live-events/watch/by-id/{public_id}/verify-token | Verify watch token |
POST | /v1/live-events/watch/by-id/{public_id}/consume-grant | Consume access grant on playback start |
GET /v1/live-events/watch/
Resolve watch state
Returns the current watch state for an event. The watch page polls this every 10 seconds to detect state changes (e.g. event goes live, replay becomes available).
Returns watch_state (viewer-facing UI state) and status (internal lifecycle). Playback objects are only included for public events — auth-required events must call verify-password or verify-token first.
Draft events are not publicly resolvable and return 404.
Response:
| Field | Type | Description |
|---|---|---|
event_id | string | Unique event identifier |
public_id | string | Global event identity used by Meil Live and branded audience URLs |
slug | string | URL-safe event identifier used in watch and embed URLs |
name | string | Event display name |
description | string | Optional event description |
status | string | Internal lifecycle state. For UI logic, use watch_state instead. Values: scheduled, ready, rehearsal, live, ending, ended, processing, failed, cancelled |
watch_state | string | Canonical viewer-facing UI state. The watch page should render based on this field. Values: not_started, access_required, live, rehearsal_hidden, processing_replay, replay_available, ended_no_replay, cancelled |
visibility_mode | string | Access control model for this event Values: public, token, password, tenant_only |
requires_auth | boolean | Whether the viewer must verify access (password, token, or login) before playback URLs are returned |
auth_type | string | Which auth method is required, if any. Null for public events. Values: password, token, tenant_only |
scheduled_start_at | string | Planned start time (ISO 8601) |
scheduled_end_at | string | Planned end time (ISO 8601) |
timezone | string | IANA timezone for display purposes |
countdown_enabled | boolean | Whether to show a countdown timer before the event starts |
playback_mode | string | Which playback path is currently active Values: live, replay, none |
live_playback | object | Live stream playback info. Present only when the event is live and the viewer has access. |
replay_playback | object | Replay playback info. Present only when the event has ended with a published replay and the viewer has access. |
embed_enabled | boolean | Whether iframe embedding is permitted for this event |
banner_url | string | Optional banner image URL for the watch page |
logo_url | string | Optional logo image URL for the watch page |
Example:
curl https://api.wayscloud.services/v1/live-events/watch/{slug} \
-H "X-API-Key: wayscloud_live_abc12_YOUR_SECRET"Response:
{
"event_id": "9a72d400-36a0-4fa5-bf7e-6883f262850a",
"public_id": "4ee07f75-9be5-4ed6-a43f-4ad9319c6436",
"slug": "product-demo",
"name": "Product Demo",
"description": "Live demo of new release features",
"status": "live",
"watch_state": "live",
"visibility_mode": "public",
"requires_auth": false,
"auth_type": null,
"scheduled_start_at": "2026-04-10T12:00:00+00:00",
"scheduled_end_at": "2026-04-10T13:30:00+00:00",
"actual_start_at": "2026-04-10T12:01:10+00:00",
"actual_end_at": null,
"timezone": "Europe/Oslo",
"countdown_enabled": false,
"playback_mode": "live",
"live_playback": {
"hls_url": "https://live.wayscloud.services/hls/live/qz0bKkTt6Vjvpb7/index.m3u8",
"protocol": "hls"
},
"replay_playback": null,
"embed_enabled": true,
"banner_url": null,
"logo_url": null,
"replay_published_at": null
}POST /v1/live-events/watch/{slug}/verify-password
Verify event password
Verifies the password for a password-protected event. On success, issues a short-lived access grant and returns the current playback information.
Failed attempts are logged for abuse detection.
Request Body:
| Field | Type | Description |
|---|---|---|
password | string | Required. Event password set by the event organizer |
Response:
| Field | Type | Description |
|---|---|---|
verified | boolean | Whether verification succeeded |
event_id | string | Internal event identifier |
public_id | string | Global event identity used by Meil Live and branded audience URLs |
access_grant | string | Short-lived access grant. Pass this to consume-grant when playback starts. |
access_grant_expires_at | string | When the access grant expires. Viewer must re-verify after expiry. |
watch_state | string | Current watch state at time of verification Values: not_started, access_required, live, rehearsal_hidden, processing_replay, replay_available, ended_no_replay, cancelled |
playback_mode | string | Which playback path is active Values: live, replay, none |
live_playback | object | Live stream info, if event is live |
replay_playback | object | Replay info, if replay is available |
Example:
curl -X POST https://api.wayscloud.services/v1/live-events/watch/{slug}/verify-password \
-H "X-API-Key: wayscloud_live_abc12_YOUR_SECRET" \
-H "Content-Type: application/json" \
-d '{
"password": "MyEventPass2026"
}'Response:
{
"verified": true,
"event_id": "9a72d400-36a0-4fa5-bf7e-6883f262850a",
"public_id": "4ee07f75-9be5-4ed6-a43f-4ad9319c6436",
"access_grant": "ag_SqW1a2RzM1PB-bNUcXyZk0pQ7wE9vF3hJ6mT8nL",
"access_grant_expires_at": "2026-04-10T15:00:00+00:00",
"watch_state": "live",
"playback_mode": "live",
"live_playback": {
"hls_url": "https://live.wayscloud.services/hls/live/qz0bKkTt6Vjvpb7/index.m3u8",
"protocol": "hls"
},
"replay_playback": null
}POST /v1/live-events/watch/{slug}/verify-token
Verify watch token
Validates an access token for a token-gated event. On success, issues a short-lived access grant and returns playback information.
The token use_count is not incremented here — it is consumed when playback actually starts via the consume-grant endpoint. This means opening the watch page and entering a token does not use up a token slot.
The token can also be supplied as a URL parameter on the watch page (?token=...) for auto-verification.
Request Body:
| Field | Type | Description |
|---|---|---|
token | string | Required. Full watch token value as received when the token was created |
Response:
| Field | Type | Description |
|---|---|---|
verified | boolean | Whether verification succeeded |
event_id | string | Internal event identifier |
public_id | string | Global event identity used by Meil Live and branded audience URLs |
access_grant | string | Short-lived access grant. Pass this to consume-grant when playback starts. |
access_grant_expires_at | string | When the access grant expires. Viewer must re-verify after expiry. |
watch_state | string | Current watch state at time of verification Values: not_started, access_required, live, rehearsal_hidden, processing_replay, replay_available, ended_no_replay, cancelled |
playback_mode | string | Which playback path is active Values: live, replay, none |
live_playback | object | Live stream info, if event is live |
replay_playback | object | Replay info, if replay is available |
Example:
curl -X POST https://api.wayscloud.services/v1/live-events/watch/{slug}/verify-token \
-H "X-API-Key: wayscloud_live_abc12_YOUR_SECRET" \
-H "Content-Type: application/json" \
-d '{
"token": "wayscloud_le_k5q2ubCC8QAx1L2RNNMn8dLQ7bEeVNTm"
}'Response:
{
"verified": true,
"event_id": "9a72d400-36a0-4fa5-bf7e-6883f262850a",
"public_id": "4ee07f75-9be5-4ed6-a43f-4ad9319c6436",
"access_grant": "ag_SqW1a2RzM1PB-bNUcXyZk0pQ7wE9vF3hJ6mT8nL",
"access_grant_expires_at": "2026-04-10T15:00:00+00:00",
"watch_state": "live",
"playback_mode": "live",
"live_playback": {
"hls_url": "https://live.wayscloud.services/hls/live/qz0bKkTt6Vjvpb7/index.m3u8",
"protocol": "hls"
},
"replay_playback": null
}POST /v1/live-events/watch/{slug}/consume-grant
Consume access grant on playback start
Called by the watch page when video playback actually starts. Marks the access grant as consumed and increments the token use_count.
This is the point where a token use is actually spent. Idempotent — calling twice with the same grant returns already_consumed: true without incrementing again.
If the grant has expired, returns 403.
Request Body:
| Field | Type | Description |
|---|---|---|
access_grant | string | Required. Access grant string (prefixed with ag_) received from verify-password or verify-token |
Response:
| Field | Type | Description |
|---|---|---|
consumed | boolean | Whether the grant was consumed |
already_consumed | boolean | True if this grant was already consumed in a previous call. Token use_count is not incremented again. |
Example:
curl -X POST https://api.wayscloud.services/v1/live-events/watch/{slug}/consume-grant \
-H "X-API-Key: wayscloud_live_abc12_YOUR_SECRET" \
-H "Content-Type: application/json" \
-d '{
"access_grant": "ag_SqW1a2RzM1PB-bNUcXyZk0pQ7wE9vF3hJ6mT8nL"
}'Response:
{
"consumed": true,
"already_consumed": false
}GET /v1/live-events/watch/by-id/
Resolve watch state
Returns the current watch state for an event. The watch page polls this every 10 seconds to detect state changes (e.g. event goes live, replay becomes available).
Returns watch_state (viewer-facing UI state) and status (internal lifecycle). Playback objects are only included for public events — auth-required events must call verify-password or verify-token first.
Draft events are not publicly resolvable and return 404.
This tenant-independent variant is for Meil Live and verified customer audience domains. Do not use a customer-local slug for new integrations.
Response:
| Field | Type | Description |
|---|---|---|
event_id | string | Unique event identifier |
public_id | string | Global event identity used by Meil Live and branded audience URLs |
slug | string | URL-safe event identifier used in watch and embed URLs |
name | string | Event display name |
description | string | Optional event description |
status | string | Internal lifecycle state. For UI logic, use watch_state instead. Values: scheduled, ready, rehearsal, live, ending, ended, processing, failed, cancelled |
watch_state | string | Canonical viewer-facing UI state. The watch page should render based on this field. Values: not_started, access_required, live, rehearsal_hidden, processing_replay, replay_available, ended_no_replay, cancelled |
visibility_mode | string | Access control model for this event Values: public, token, password, tenant_only |
requires_auth | boolean | Whether the viewer must verify access (password, token, or login) before playback URLs are returned |
auth_type | string | Which auth method is required, if any. Null for public events. Values: password, token, tenant_only |
scheduled_start_at | string | Planned start time (ISO 8601) |
scheduled_end_at | string | Planned end time (ISO 8601) |
timezone | string | IANA timezone for display purposes |
countdown_enabled | boolean | Whether to show a countdown timer before the event starts |
playback_mode | string | Which playback path is currently active Values: live, replay, none |
live_playback | object | Live stream playback info. Present only when the event is live and the viewer has access. |
replay_playback | object | Replay playback info. Present only when the event has ended with a published replay and the viewer has access. |
embed_enabled | boolean | Whether iframe embedding is permitted for this event |
banner_url | string | Optional banner image URL for the watch page |
logo_url | string | Optional logo image URL for the watch page |
Example:
curl https://api.wayscloud.services/v1/live-events/watch/by-id/{public_id} \
-H "X-API-Key: wayscloud_live_abc12_YOUR_SECRET"Response:
{
"event_id": "9a72d400-36a0-4fa5-bf7e-6883f262850a",
"public_id": "4ee07f75-9be5-4ed6-a43f-4ad9319c6436",
"slug": "product-demo",
"name": "Product Demo",
"description": "Live demo of new release features",
"status": "live",
"watch_state": "live",
"visibility_mode": "public",
"requires_auth": false,
"auth_type": null,
"scheduled_start_at": "2026-04-10T12:00:00+00:00",
"scheduled_end_at": "2026-04-10T13:30:00+00:00",
"actual_start_at": "2026-04-10T12:01:10+00:00",
"actual_end_at": null,
"timezone": "Europe/Oslo",
"countdown_enabled": false,
"playback_mode": "live",
"live_playback": {
"hls_url": "https://live.wayscloud.services/hls/live/qz0bKkTt6Vjvpb7/index.m3u8",
"protocol": "hls"
},
"replay_playback": null,
"embed_enabled": true,
"banner_url": null,
"logo_url": null,
"replay_published_at": null
}POST /v1/live-events/watch/by-id/{public_id}/verify-password
Verify event password
Verifies the password for a password-protected event. On success, issues a short-lived access grant and returns the current playback information.
Failed attempts are logged for abuse detection.
This tenant-independent variant is for Meil Live and verified customer audience domains. Do not use a customer-local slug for new integrations.
Request Body:
| Field | Type | Description |
|---|---|---|
password | string | Required. Event password set by the event organizer |
Response:
| Field | Type | Description |
|---|---|---|
verified | boolean | Whether verification succeeded |
event_id | string | Internal event identifier |
public_id | string | Global event identity used by Meil Live and branded audience URLs |
access_grant | string | Short-lived access grant. Pass this to consume-grant when playback starts. |
access_grant_expires_at | string | When the access grant expires. Viewer must re-verify after expiry. |
watch_state | string | Current watch state at time of verification Values: not_started, access_required, live, rehearsal_hidden, processing_replay, replay_available, ended_no_replay, cancelled |
playback_mode | string | Which playback path is active Values: live, replay, none |
live_playback | object | Live stream info, if event is live |
replay_playback | object | Replay info, if replay is available |
Example:
curl -X POST https://api.wayscloud.services/v1/live-events/watch/by-id/{public_id}/verify-password \
-H "X-API-Key: wayscloud_live_abc12_YOUR_SECRET" \
-H "Content-Type: application/json" \
-d '{
"password": "MyEventPass2026"
}'Response:
{
"verified": true,
"event_id": "9a72d400-36a0-4fa5-bf7e-6883f262850a",
"public_id": "4ee07f75-9be5-4ed6-a43f-4ad9319c6436",
"access_grant": "ag_SqW1a2RzM1PB-bNUcXyZk0pQ7wE9vF3hJ6mT8nL",
"access_grant_expires_at": "2026-04-10T15:00:00+00:00",
"watch_state": "live",
"playback_mode": "live",
"live_playback": {
"hls_url": "https://live.wayscloud.services/hls/live/qz0bKkTt6Vjvpb7/index.m3u8",
"protocol": "hls"
},
"replay_playback": null
}POST /v1/live-events/watch/by-id/{public_id}/verify-token
Verify watch token
Validates an access token for a token-gated event. On success, issues a short-lived access grant and returns playback information.
The token use_count is not incremented here — it is consumed when playback actually starts via the consume-grant endpoint. This means opening the watch page and entering a token does not use up a token slot.
The token can also be supplied as a URL parameter on the watch page (?token=...) for auto-verification.
This tenant-independent variant is for Meil Live and verified customer audience domains. Do not use a customer-local slug for new integrations.
Request Body:
| Field | Type | Description |
|---|---|---|
token | string | Required. Full watch token value as received when the token was created |
Response:
| Field | Type | Description |
|---|---|---|
verified | boolean | Whether verification succeeded |
event_id | string | Internal event identifier |
public_id | string | Global event identity used by Meil Live and branded audience URLs |
access_grant | string | Short-lived access grant. Pass this to consume-grant when playback starts. |
access_grant_expires_at | string | When the access grant expires. Viewer must re-verify after expiry. |
watch_state | string | Current watch state at time of verification Values: not_started, access_required, live, rehearsal_hidden, processing_replay, replay_available, ended_no_replay, cancelled |
playback_mode | string | Which playback path is active Values: live, replay, none |
live_playback | object | Live stream info, if event is live |
replay_playback | object | Replay info, if replay is available |
Example:
curl -X POST https://api.wayscloud.services/v1/live-events/watch/by-id/{public_id}/verify-token \
-H "X-API-Key: wayscloud_live_abc12_YOUR_SECRET" \
-H "Content-Type: application/json" \
-d '{
"token": "wayscloud_le_k5q2ubCC8QAx1L2RNNMn8dLQ7bEeVNTm"
}'Response:
{
"verified": true,
"event_id": "9a72d400-36a0-4fa5-bf7e-6883f262850a",
"public_id": "4ee07f75-9be5-4ed6-a43f-4ad9319c6436",
"access_grant": "ag_SqW1a2RzM1PB-bNUcXyZk0pQ7wE9vF3hJ6mT8nL",
"access_grant_expires_at": "2026-04-10T15:00:00+00:00",
"watch_state": "live",
"playback_mode": "live",
"live_playback": {
"hls_url": "https://live.wayscloud.services/hls/live/qz0bKkTt6Vjvpb7/index.m3u8",
"protocol": "hls"
},
"replay_playback": null
}POST /v1/live-events/watch/by-id/{public_id}/consume-grant
Consume access grant on playback start
Called by the watch page when video playback actually starts. Marks the access grant as consumed and increments the token use_count.
This is the point where a token use is actually spent. Idempotent — calling twice with the same grant returns already_consumed: true without incrementing again.
If the grant has expired, returns 403.
This tenant-independent variant is for Meil Live and verified customer audience domains. Do not use a customer-local slug for new integrations.
Request Body:
| Field | Type | Description |
|---|---|---|
access_grant | string | Required. Access grant string (prefixed with ag_) received from verify-password or verify-token |
Response:
| Field | Type | Description |
|---|---|---|
consumed | boolean | Whether the grant was consumed |
already_consumed | boolean | True if this grant was already consumed in a previous call. Token use_count is not incremented again. |
Example:
curl -X POST https://api.wayscloud.services/v1/live-events/watch/by-id/{public_id}/consume-grant \
-H "X-API-Key: wayscloud_live_abc12_YOUR_SECRET" \
-H "Content-Type: application/json" \
-d '{
"access_grant": "ag_SqW1a2RzM1PB-bNUcXyZk0pQ7wE9vF3hJ6mT8nL"
}'Response:
{
"consumed": true,
"already_consumed": false
}