> For the complete documentation index, see [llms.txt](https://docs.decentraland.org/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.decentraland.org/apis/apis/comms-gatekeeper/cast-2.0.md).

# Cast 2.0

## Get streamer token

> Generates LiveKit credentials for a streamer to broadcast in a scene.\
> This endpoint validates a streaming token and provides the necessary\
> credentials for a streamer to connect to the LiveKit room and start streaming.\
> No authentication required - uses streaming token for validation.<br>

```json
{"openapi":"3.0.0","info":{"title":"Comms Gatekeeper API","version":"1.0.0"},"servers":[{"url":"https://comms-gatekeeper.decentraland.org","description":"Production server"},{"url":"https://comms-gatekeeper.decentraland.zone","description":"Development server"}],"security":[],"paths":{"/cast/streamer-token":{"post":{"operationId":"getStreamerToken","summary":"Get streamer token","description":"Generates LiveKit credentials for a streamer to broadcast in a scene.\nThis endpoint validates a streaming token and provides the necessary\ncredentials for a streamer to connect to the LiveKit room and start streaming.\nNo authentication required - uses streaming token for validation.\n","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["token","identity"],"properties":{"token":{"type":"string","description":"Streaming token for authentication"},"identity":{"type":"string","description":"Display name for the streamer"}}}}}},"responses":{"200":{"description":"Streamer token generated successfully","content":{"application/json":{"schema":{"type":"object","required":["url","token","roomId","identity"],"properties":{"url":{"type":"string","description":"LiveKit connection URL"},"token":{"type":"string","description":"LiveKit JWT token for authentication"},"roomId":{"type":"string","description":"LiveKit room ID"},"identity":{"type":"string","description":"Unique internal identity for the streamer"}}}}}},"400":{"description":"Invalid request - Missing required fields","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"string","description":"Error message describing what went wrong"}}}}}},"401":{"description":"Unauthorized - Invalid or expired streaming token","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"string","description":"Error message describing what went wrong"}}}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"string","description":"Error message describing what went wrong"}}}}}}},"tags":["Cast 2.0"]}}}}
```

## Get watcher token

> Generates LiveKit credentials for a watcher to view streams in a location.\
> This endpoint allows users to join as viewers in a specific location (parcel or world)\
> and watch active streams.\
> \
> Requires Signed Fetch authentication from a wallet (a \`decentraland-kernel-scene\` signer is\
> rejected: viewers are end users, not scenes). A verified wallet is required because\
> watchers join the scene's real comms room, so both scene bans and platform bans are\
> enforced against it — either one is rejected with \`403\`.<br>

```json
{"openapi":"3.0.0","info":{"title":"Comms Gatekeeper API","version":"1.0.0"},"servers":[{"url":"https://comms-gatekeeper.decentraland.org","description":"Production server"},{"url":"https://comms-gatekeeper.decentraland.zone","description":"Development server"}],"security":[{"SignedFetch":[]}],"components":{"securitySchemes":{"SignedFetch":{"type":"apiKey","in":"header","name":"x-identity","description":"Signed Fetch authentication for scene-based requests.\nRequires a chain of identity headers:\n- x-identity-auth-chain-0: Signer information\n- x-identity-auth-chain-1: Ephemeral key information  \n- x-identity-auth-chain-2: Signed entity information\n- x-identity-timestamp: Request timestamp\n- x-identity-metadata: Request metadata\nUsed for authentication from decentraland-kernel-scene.\n"}}},"paths":{"/cast/watcher-token":{"post":{"operationId":"getWatcherToken","summary":"Get watcher token","description":"Generates LiveKit credentials for a watcher to view streams in a location.\nThis endpoint allows users to join as viewers in a specific location (parcel or world)\nand watch active streams.\n\nRequires Signed Fetch authentication from a wallet (a `decentraland-kernel-scene` signer is\nrejected: viewers are end users, not scenes). A verified wallet is required because\nwatchers join the scene's real comms room, so both scene bans and platform bans are\nenforced against it — either one is rejected with `403`.\n","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["location","identity"],"properties":{"location":{"type":"string","description":"Location (parcel coordinates or world name)"},"identity":{"type":"string","description":"Display name for the watcher"}}}}}},"responses":{"200":{"description":"Watcher token generated successfully","content":{"application/json":{"schema":{"type":"object","required":["url","token","roomId","identity"],"properties":{"url":{"type":"string","description":"LiveKit connection URL"},"token":{"type":"string","description":"LiveKit JWT token for authentication"},"roomId":{"type":"string","description":"LiveKit room ID"},"identity":{"type":"string","description":"Unique internal identity for the watcher"},"placeName":{"type":"string","description":"Name of the place being watched"}}}}}},"400":{"description":"Invalid request - Missing required fields","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"string","description":"Error message describing what went wrong"}}}}}},"401":{"description":"Unauthorized - No active stream found for location","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"string","description":"Error message describing what went wrong"}}}}}},"403":{"description":"Forbidden - The watcher has an active platform ban (or last connected from a banned device), or is banned from the scene","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"string","description":"Error message describing what went wrong"}}}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"string","description":"Error message describing what went wrong"}}}}}}},"tags":["Cast 2.0"]}}}}
```

## Generate stream link

> Generates a unique stream link for a scene that allows streamers to broadcast\
> and watchers to view the stream. Only scene administrators can generate stream links.\
> The generated link expires after 4 days.\
> Requires Signed Fetch authentication from decentraland-kernel-scene.\
> Must include the complete identity header chain: x-identity-auth-chain-0, x-identity-auth-chain-1, x-identity-auth-chain-2, x-identity-timestamp, and x-identity-metadata.\
> \
> Rejected with \`403\` when the caller has an active platform ban, checked before the scene\
> admin lookup so the response never doubles as an admin-status oracle. The local-preview\
> branch (\`ALLOW\_LOCAL\_PREVIEW\` with a preview realm name) is gated too, even though it\
> skips the admin check.\
> \
> This is the only wallet-scoped gate on the streaming path: \`POST /cast/streamer-token\`\
> authenticates a streaming key rather than a wallet, so a key minted before the ban keeps\
> working until it expires.<br>

```json
{"openapi":"3.0.0","info":{"title":"Comms Gatekeeper API","version":"1.0.0"},"servers":[{"url":"https://comms-gatekeeper.decentraland.org","description":"Production server"},{"url":"https://comms-gatekeeper.decentraland.zone","description":"Development server"}],"security":[{"SignedFetch":[]}],"components":{"securitySchemes":{"SignedFetch":{"type":"apiKey","in":"header","name":"x-identity","description":"Signed Fetch authentication for scene-based requests.\nRequires a chain of identity headers:\n- x-identity-auth-chain-0: Signer information\n- x-identity-auth-chain-1: Ephemeral key information  \n- x-identity-auth-chain-2: Signed entity information\n- x-identity-timestamp: Request timestamp\n- x-identity-metadata: Request metadata\nUsed for authentication from decentraland-kernel-scene.\n"}}},"paths":{"/cast/generate-stream-link":{"get":{"operationId":"generateStreamLink","summary":"Generate stream link","description":"Generates a unique stream link for a scene that allows streamers to broadcast\nand watchers to view the stream. Only scene administrators can generate stream links.\nThe generated link expires after 4 days.\nRequires Signed Fetch authentication from decentraland-kernel-scene.\nMust include the complete identity header chain: x-identity-auth-chain-0, x-identity-auth-chain-1, x-identity-auth-chain-2, x-identity-timestamp, and x-identity-metadata.\n\nRejected with `403` when the caller has an active platform ban, checked before the scene\nadmin lookup so the response never doubles as an admin-status oracle. The local-preview\nbranch (`ALLOW_LOCAL_PREVIEW` with a preview realm name) is gated too, even though it\nskips the admin check.\n\nThis is the only wallet-scoped gate on the streaming path: `POST /cast/streamer-token`\nauthenticates a streaming key rather than a wallet, so a key minted before the ban keeps\nworking until it expires.\n","responses":{"200":{"description":"Stream link generated successfully","content":{"application/json":{"schema":{"type":"object","required":["streamLink","watcherLink","streamingKey","placeId","placeName","expiresAt","expiresInDays"],"properties":{"streamLink":{"type":"string","description":"URL for streamers to access the stream"},"watcherLink":{"type":"string","description":"URL for watchers to access the stream"},"streamingKey":{"type":"string","description":"Unique streaming key for authentication"},"placeId":{"type":"string","description":"ID of the place"},"placeName":{"type":"string","description":"Name of the place"},"expiresAt":{"type":"string","format":"date-time","description":"Expiration timestamp in ISO format"},"expiresInDays":{"type":"integer","description":"Number of days until expiration"}}}}}},"400":{"description":"Invalid request - Missing required fields or invalid scene data","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"string","description":"Error message describing what went wrong"}}}}}},"401":{"description":"Unauthorized - Authentication required or insufficient permissions","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"string","description":"Error message describing what went wrong"}}}}}},"403":{"description":"Forbidden - The caller has an active platform ban, or last connected from a banned device","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"string","description":"Error message describing what went wrong"}}}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"string","description":"Error message describing what went wrong"}}}}}}},"tags":["Cast 2.0"]}}}}
```

## Get stream information

> Retrieves information about a stream using its streaming key.\
> This endpoint provides details about the place, location, and stream status.\
> No authentication required.<br>

```json
{"openapi":"3.0.0","info":{"title":"Comms Gatekeeper API","version":"1.0.0"},"servers":[{"url":"https://comms-gatekeeper.decentraland.org","description":"Production server"},{"url":"https://comms-gatekeeper.decentraland.zone","description":"Development server"}],"security":[],"paths":{"/cast/stream-info/{streamingKey}":{"get":{"operationId":"getStreamInfo","summary":"Get stream information","description":"Retrieves information about a stream using its streaming key.\nThis endpoint provides details about the place, location, and stream status.\nNo authentication required.\n","parameters":[{"name":"streamingKey","in":"path","required":true,"schema":{"type":"string"},"description":"Streaming key for the stream"}],"responses":{"200":{"description":"Stream information retrieved successfully","content":{"application/json":{"schema":{"type":"object","required":["placeName","placeId","location","isWorld"],"properties":{"placeName":{"type":"string","description":"Name of the place"},"placeId":{"type":"string","description":"ID of the place"},"location":{"type":"string","description":"Location identifier (world name or parcel coordinates)"},"isWorld":{"type":"boolean","description":"Whether this is a world or a parcel"}}}}}},"400":{"description":"Invalid request - Invalid streaming key","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"string","description":"Error message describing what went wrong"}}}}}},"404":{"description":"Stream not found or expired","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"string","description":"Error message describing what went wrong"}}}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"string","description":"Error message describing what went wrong"}}}}}}},"tags":["Cast 2.0"]}}}}
```

## Generate presentation bot token

> Generates a LiveKit token for a presentation bot to join a cast room.\
> The bot uses this token to connect to the room and manage presentations.\
> No authentication required - uses streaming key for validation.<br>

```json
{"openapi":"3.0.0","info":{"title":"Comms Gatekeeper API","version":"1.0.0"},"servers":[{"url":"https://comms-gatekeeper.decentraland.org","description":"Production server"},{"url":"https://comms-gatekeeper.decentraland.zone","description":"Development server"}],"security":[],"paths":{"/cast/presentation-bot-token":{"post":{"operationId":"generatePresentationBotToken","summary":"Generate presentation bot token","description":"Generates a LiveKit token for a presentation bot to join a cast room.\nThe bot uses this token to connect to the room and manage presentations.\nNo authentication required - uses streaming key for validation.\n","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["streamingKey"],"properties":{"streamingKey":{"type":"string","description":"Streaming key to generate presentation bot token for"}}}}}},"responses":{"200":{"description":"Presentation bot token generated successfully","content":{"application/json":{"schema":{"type":"object","required":["token","roomId"],"properties":{"token":{"type":"string","description":"LiveKit JWT token for the presentation bot"},"roomId":{"type":"string","description":"LiveKit room ID the bot can join"}}}}}},"400":{"description":"Invalid request - Missing or invalid streaming key","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"string","description":"Error message describing what went wrong"}}}}}},"401":{"description":"Unauthorized - Invalid or expired streaming key","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"string","description":"Error message describing what went wrong"}}}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"string","description":"Error message describing what went wrong"}}}}}}},"tags":["Cast 2.0"]}}}}
```

## List presenters in a room

> Returns the list of participants with the presenter role in a cast room.\
> The roomId is derived server-side from the Signed Fetch auth metadata (sceneId + realm).\
> Only scene administrators can list presenters.\
> Requires Signed Fetch authentication.<br>

```json
{"openapi":"3.0.0","info":{"title":"Comms Gatekeeper API","version":"1.0.0"},"servers":[{"url":"https://comms-gatekeeper.decentraland.org","description":"Production server"},{"url":"https://comms-gatekeeper.decentraland.zone","description":"Development server"}],"security":[{"SignedFetch":[]}],"components":{"securitySchemes":{"SignedFetch":{"type":"apiKey","in":"header","name":"x-identity","description":"Signed Fetch authentication for scene-based requests.\nRequires a chain of identity headers:\n- x-identity-auth-chain-0: Signer information\n- x-identity-auth-chain-1: Ephemeral key information  \n- x-identity-auth-chain-2: Signed entity information\n- x-identity-timestamp: Request timestamp\n- x-identity-metadata: Request metadata\nUsed for authentication from decentraland-kernel-scene.\n"}}},"paths":{"/cast/presenters":{"get":{"operationId":"getPresenters","summary":"List presenters in a room","description":"Returns the list of participants with the presenter role in a cast room.\nThe roomId is derived server-side from the Signed Fetch auth metadata (sceneId + realm).\nOnly scene administrators can list presenters.\nRequires Signed Fetch authentication.\n","responses":{"200":{"description":"Presenters listed successfully","content":{"application/json":{"schema":{"type":"object","required":["presenters"],"properties":{"presenters":{"type":"array","items":{"type":"string"},"description":"List of participant identities with presenter role"}}}}}},"401":{"description":"Unauthorized - Not a scene administrator","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"string","description":"Error message describing what went wrong"}}}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"string","description":"Error message describing what went wrong"}}}}}}},"tags":["Cast 2.0"]}}}}
```

## Promote participant to presenter

> Promotes a participant in a cast room to the presenter role, allowing them\
> to share content. The roomId is derived server-side from the Signed Fetch\
> auth metadata (sceneId + realm). Only scene administrators can promote presenters.\
> Requires Signed Fetch authentication.<br>

```json
{"openapi":"3.0.0","info":{"title":"Comms Gatekeeper API","version":"1.0.0"},"servers":[{"url":"https://comms-gatekeeper.decentraland.org","description":"Production server"},{"url":"https://comms-gatekeeper.decentraland.zone","description":"Development server"}],"security":[{"SignedFetch":[]}],"components":{"securitySchemes":{"SignedFetch":{"type":"apiKey","in":"header","name":"x-identity","description":"Signed Fetch authentication for scene-based requests.\nRequires a chain of identity headers:\n- x-identity-auth-chain-0: Signer information\n- x-identity-auth-chain-1: Ephemeral key information  \n- x-identity-auth-chain-2: Signed entity information\n- x-identity-timestamp: Request timestamp\n- x-identity-metadata: Request metadata\nUsed for authentication from decentraland-kernel-scene.\n"}}},"paths":{"/cast/presenters/{participantIdentity}":{"put":{"operationId":"promotePresenter","summary":"Promote participant to presenter","description":"Promotes a participant in a cast room to the presenter role, allowing them\nto share content. The roomId is derived server-side from the Signed Fetch\nauth metadata (sceneId + realm). Only scene administrators can promote presenters.\nRequires Signed Fetch authentication.\n","parameters":[{"name":"participantIdentity","in":"path","required":true,"schema":{"type":"string","pattern":"^0x[0-9a-fA-F]{40}$"},"description":"Ethereum address of the participant to promote (0x + 40 hex characters)"}],"responses":{"200":{"description":"Participant promoted to presenter","content":{"application/json":{"schema":{"type":"object","required":["message"],"properties":{"message":{"type":"string","description":"Success message"}}}}}},"400":{"description":"Invalid participantIdentity format","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"string","description":"Error message describing what went wrong"}}}}}},"401":{"description":"Unauthorized - Not a scene administrator or no active stream","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"string","description":"Error message describing what went wrong"}}}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"string","description":"Error message describing what went wrong"}}}}}}},"tags":["Cast 2.0"]}}}}
```

## Demote presenter to watcher

> Demotes a presenter back to the watcher role, revoking their ability to\
> share content. The roomId is derived server-side from the Signed Fetch\
> auth metadata (sceneId + realm). Only scene administrators can demote presenters.\
> Requires Signed Fetch authentication.<br>

```json
{"openapi":"3.0.0","info":{"title":"Comms Gatekeeper API","version":"1.0.0"},"servers":[{"url":"https://comms-gatekeeper.decentraland.org","description":"Production server"},{"url":"https://comms-gatekeeper.decentraland.zone","description":"Development server"}],"security":[{"SignedFetch":[]}],"components":{"securitySchemes":{"SignedFetch":{"type":"apiKey","in":"header","name":"x-identity","description":"Signed Fetch authentication for scene-based requests.\nRequires a chain of identity headers:\n- x-identity-auth-chain-0: Signer information\n- x-identity-auth-chain-1: Ephemeral key information  \n- x-identity-auth-chain-2: Signed entity information\n- x-identity-timestamp: Request timestamp\n- x-identity-metadata: Request metadata\nUsed for authentication from decentraland-kernel-scene.\n"}}},"paths":{"/cast/presenters/{participantIdentity}":{"delete":{"operationId":"demotePresenter","summary":"Demote presenter to watcher","description":"Demotes a presenter back to the watcher role, revoking their ability to\nshare content. The roomId is derived server-side from the Signed Fetch\nauth metadata (sceneId + realm). Only scene administrators can demote presenters.\nRequires Signed Fetch authentication.\n","parameters":[{"name":"participantIdentity","in":"path","required":true,"schema":{"type":"string","pattern":"^0x[0-9a-fA-F]{40}$"},"description":"Ethereum address of the participant to demote (0x + 40 hex characters)"}],"responses":{"200":{"description":"Participant demoted from presenter","content":{"application/json":{"schema":{"type":"object","required":["message"],"properties":{"message":{"type":"string","description":"Success message"}}}}}},"400":{"description":"Invalid participantIdentity format","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"string","description":"Error message describing what went wrong"}}}}}},"401":{"description":"Unauthorized - Not a scene administrator or no active stream","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"string","description":"Error message describing what went wrong"}}}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"string","description":"Error message describing what went wrong"}}}}}}},"tags":["Cast 2.0"]}}}}
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.decentraland.org/apis/apis/comms-gatekeeper/cast-2.0.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
