API
The Ingress API is available within the server SDKs and the CLI:
CreateIngress
WHIP / RTMP example
To provision an ingress with the Ingress service, use the CreateIngress API. It returns an IngressInfo object that describes the created ingress, along with connection settings. These parameters can also be queried at any time using the ListIngress API
Create a file at ingress.json with the following content:
{"input_type": 0 for RTMP, 1 for WHIP"name": "Name of the ingress goes here","room_name": "Name of the room to connect to","participant_identity": "Unique identity for the room participant the Ingress service will connect as","participant_name": "Name displayed in the room for the participant","enable_transcoding": true // Transcode the input stream. Can only be false for WHIP,}
Then create the ingress using lk:
export LIVEKIT_URL=https://my-livekit-hostexport LIVEKIT_API_KEY=livekit-api-keyexport LIVEKIT_API_SECRET=livekit-api-secretlk ingress create ingress.json
import { IngressClient, IngressInfo, IngressInput } from 'livekit-server-sdk';const livekitHost = 'https://my-livekit-host';const ingressClient = new IngressClient(livekitHost, 'api-key', 'secret-key');const ingress = {name: 'my-ingress',roomName: 'my-room',participantIdentity: 'my-participant',participantName: 'My Participant',// Transcode the input stream. Can only be false for WHIP.enableTranscoding: false,};// Use IngressInput.WHIP_INPUT to create a WHIP endpointawait ingressClient.createIngress(IngressInput.RTMP_INPUT, ingress);
ctx := context.Background()ingressClient := lksdk.NewIngressClient("https://my-livekit-host","livekit-api-key","livekit-api-secret",)t := trueingressRequest := &livekit.CreateIngressRequest{InputType: livekit.IngressInput_RTMP_INPUT, // Or livekit.IngressInput_WHIP_INPUTName: "my-ingress",RoomName: "my-room",ParticipantIdentity: "my-participant",ParticipantName: "My Participant",// Transcode the input stream. Can only be false for WHIP.EnableTranscoding: &t,}info, err := ingressClient.CreateIngress(ctx, ingressRequest)ingressID := info.IngressId
ingressClient = LiveKit::IngressServiceClient.new(url, api_key: "yourkey", api_secret: "yoursecret")info = ingressClient.create_ingress(:RTMP_INPUT, # Or WHIP_INPUTname: "my-ingress",room_name: "my-room",participant_identity: "my-participant",participant_name: "My Participant",)puts info.ingress_id
URL Input example
With URL Input, ingress will begin immediately after CreateIngress is called. URL_INPUT ingress can't be reused.
Create a file at ingress.json with the following content:
{"input_type": "URL_INPUT", // or 2"name": "Name of the ingress goes here","room_name": "Name of the room to connect to","participant_identity": "Unique identity for the room participant the Ingress service will connect as","participant_name": "Name displayed in the room for the participant","url": "HTTP(S) or SRT url to the file or stream"}
Then create the ingress using lk:
export LIVEKIT_URL=https://my-livekit-hostexport LIVEKIT_API_KEY=livekit-api-keyexport LIVEKIT_API_SECRET=livekit-api-secretlk ingress create ingress.json
import { IngressClient, IngressInfo, IngressInput } from 'livekit-server-sdk';const livekitHost = 'https://my-livekit-host';const ingressClient = new IngressClient(livekitHost, 'api-key', 'secret-key');const ingress = {name: 'my-ingress',roomName: 'my-room',participantIdentity: 'my-participant',participantName: 'My Participant',url: 'https://domain.com/video.m3u8', // or 'srt://domain.com:7001'};await ingressClient.createIngress(IngressInput.URL_INPUT, ingress);
ctx := context.Background()ingressClient := lksdk.NewIngressClient("https://my-livekit-host","livekit-api-key","livekit-api-secret",)ingressRequest := &livekit.CreateIngressRequest{InputType: livekit.IngressInput_URL_INPUT,Name: "my-ingress",RoomName: "my-room",ParticipantIdentity: "my-participant",ParticipantName: "My Participant",Url: "https://domain.com/video.m3u8", // or 'srt://domain.com:7001'}info, err := ingressClient.CreateIngress(ctx, ingressRequest)ingressID := info.IngressId
ingressClient = LiveKit::IngressServiceClient.new(url, api_key: "yourkey", api_secret: "yoursecret")info = ingressClient.create_ingress(:URL_INPUT,name: "my-ingress",room_name: "my-room",participant_identity: "my-participant",participant_name: "My Participant",url: "https://domain.com/video.m3u8", # or 'srt://domain.com:7001')puts info.ingress_id
ListIngress
lk ingress list
The optional --room option allows to restrict the output to the Ingress associated to a given room. The --id option can check if a specific ingress is active.
await ingressClient.listIngress('my-room');
The roomName parameter can be left empty to list all Ingress.
listRequest := &livekit.ListIngressRequest{RoomName: "my-room", // Optional parameter to restrict the list to only one room. Leave empty to list all Ingress.}infoArray, err := ingressClient.ListIngress(ctx, listRequest)
puts ingressClient.list_ingress(# optionalroom_name: "my-room")
UpdateIngress
The ingress configuration can be updated using the UpdateIngress API. This enables the ability to reuse the same ingress URL to publish to different rooms. Only reusable ingresses, such as RTMP or WHIP, can be updated.
Create a file at ingress.json with the fields to be updated.
{"ingress_id": "Ingress ID of the ingress to update","name": "Name of the ingress goes here","room_name": "Name of the room to connect to","participant_identity": "Unique identity for the room participant the Ingress service will connect as","participant_name": "Name displayed in the room for the participant"}
The only required field is ingress_id. Non-provided fields are left unchanged.
lk ingress update ingress.json
const update = {name: 'my-other-ingress',roomName: 'my-other-room',participantIdentity: 'my-other-participant',participantName: 'My Other Participant',};await ingressClient.updateIngress(ingressID, update);
Parameters left empty in the update object are left unchanged.
updateRequest := &livekit.UpdateIngressRequest{IngressId: "ingressID", // required parameter indicating what Ingress to updateName: "my-other-ingress",RoomName: "my-other-room",ParticipantIdentity: "my-other-participant",ParticipantName: "My Other Participant",}info, err := ingressClient.UpdateIngress(ctx, updateRequest)
Non specified fields are left unchanged.
# only specified fields are updated, all fields are optionalputs ingressClient.update_ingress("ingress-id",name: "ingress-name",room_name: "my-room",participant_identity: "my-participant",participant_name: "My Participant",audio: LiveKit::Proto::IngressAudioOptions.new(...),video: LiveKit::Proto::IngressVideoOptions.new(...),)
DeleteIngress
An ingress can be reused multiple times. When not needed anymore, it can be deleted using the DeleteIngress API:
lk ingress delete <INGRESS_ID>
await ingressClient.deleteIngress('ingress_id');
deleteRequest := &livekit.DeleteIngressRequest{IngressId: "ingress_id",}info, err := ingressClient.DeleteIngress(ctx, deleteRequest)
puts ingressClient.delete_ingress("ingress-id")
Types
The Ingress service includes the following types.
ListIngressResponse
| Field | Type | Description |
|---|---|---|
| items | array<IngressInfo> | List of ingress endpoints. |
| next_page_token | TokenPagination | Token for the next page of results. |
IngressInfo
Describes the ingress and its connection settings.
| Field | Type | Description |
|---|---|---|
| ingress_id | string | Unique ingress ID. |
| name | string | User-provided identifier for the ingress. |
| stream_key | string | Stream key for the encoder (RTMP). |
| url | string | URL for the encoder (RTMP, WHIP) or source to pull from (URL input). Format depends on input type: rtmp:// for RTMP, http:// for URL. |
| input_type | IngressInput | Type of input. |
| enable_transcoding | bool | Whether transcoding is enabled. |
| audio | IngressAudioOptions | Audio options. |
| video | IngressVideoOptions | Video options. |
| room_name | string | Room the ingress publishes to. |
| participant_identity | string | Identity of the publishing participant. |
| participant_name | string | Display name of the publishing participant. |
| participant_metadata | string | Metadata associated with the publishing participant. |
| reusable | bool | Whether the ingress can be reused (e.g. for another room). |
| state | IngressState | Current state, including error or debug info (bitrate, resolution, bandwidth). |
| enabled | bool | When false, new connection attempts are rejected. Default is true. |
IngressState
Describes current endpoint status, errors, and input media state.
| Field | Type | Description |
|---|---|---|
| status | IngressState.Status | Endpoint status. |
| error | string | Error or non-compliance description, if any. |
| video | InputVideoState | Incoming video state. |
| audio | InputAudioState | Incoming audio state. |
| room_id | string | ID of the current or previous room published to. |
| started_at | int64 | When the endpoint started publishing. |
| ended_at | int64 | When the endpoint stopped publishing. |
| updated_at | int64 | Last update timestamp. |
| resource_id | string | Resource identifier. |
| tracks | array<TrackInfo> | Published track info. |
IngressState.Status
Enum. Endpoint status values:
| Name | Value | Description |
|---|---|---|
| ENDPOINT_INACTIVE | 0 | Endpoint is inactive. |
| ENDPOINT_BUFFERING | 1 | Endpoint is buffering. |
| ENDPOINT_PUBLISHING | 2 | Endpoint is publishing. |
| ENDPOINT_ERROR | 3 | Endpoint encountered an error. |
| ENDPOINT_COMPLETE | 4 | Endpoint finished (e.g. stream ended). |
InputVideoState
State of the incoming video input.
| Field | Type | Description |
|---|---|---|
| mime_type | string | MIME type of the video. |
| average_bitrate | uint32 | Average bitrate in bps. |
| width | uint32 | Frame width in pixels. |
| height | uint32 | Frame height in pixels. |
| framerate | double | Frame rate. |
InputAudioState
State of the incoming audio input.
| Field | Type | Description |
|---|---|---|
| mime_type | string | MIME type of the audio. |
| average_bitrate | uint32 | Average bitrate in bps. |
| channels | uint32 | Number of audio channels. |
| sample_rate | uint32 | Sample rate in Hz. |
IngressInput
Enum. Type of ingress input:
| Name | Value | Description |
|---|---|---|
| RTMP_INPUT | 0 | RTMP push input. |
| WHIP_INPUT | 1 | WHIP push input. |
| URL_INPUT | 2 | Pull from a URL. Only HTTP URLs supported (single media file or HLS stream). |
IngressAudioOptions
| Field | Type | Description |
|---|---|---|
| name | string | Track name. |
| source | TrackSource | Track source. |
| encoding_options | IngressAudioEncodingPreset or IngressAudioEncodingOptions | Preset or custom encoding options. |
IngressVideoOptions
| Field | Type | Description |
|---|---|---|
| name | string | Track name. |
| source | TrackSource | Track source. |
| encoding_options | IngressVideoEncodingPreset or IngressVideoEncodingOptions | Preset or custom encoding options. |
IngressAudioEncodingPreset
Enum. Audio encoding presets:
| Name | Value | Description |
|---|---|---|
| OPUS_STEREO_96KBPS | 0 | OPUS, 2 channels, 96 kbps. |
| OPUS_MONO_64KBS | 1 | OPUS, 1 channel, 64 kbps. |
IngressVideoEncodingPreset
Enum. Video encoding presets:
| Name | Value | Description |
|---|---|---|
| H264_720P_30FPS_3_LAYERS | 0 | 1280×720, 30 fps, 1900 kbps main layer, 3 layers total. |
| H264_1080P_30FPS_3_LAYERS | 1 | 1920×1080, 30 fps, 3500 kbps main layer, 3 layers total. |
| H264_540P_25FPS_2_LAYERS | 2 | 960×540, 25 fps, 1000 kbps main layer, 2 layers total. |
| H264_720P_30FPS_1_LAYER | 3 | 1280×720, 30 fps, 1900 kbps, no simulcast. |
| H264_1080P_30FPS_1_LAYER | 4 | 1920×1080, 30 fps, 3500 kbps, no simulcast. |
| H264_720P_30FPS_3_LAYERS_HIGH_MOTION | 5 | 1280×720, 30 fps, 2500 kbps main layer, 3 layers, higher bitrate for high motion. |
| H264_1080P_30FPS_3_LAYERS_HIGH_MOTION | 6 | 1920×1080, 30 fps, 4500 kbps main layer, 3 layers, higher bitrate for high motion. |
| H264_540P_25FPS_2_LAYERS_HIGH_MOTION | 7 | 960×540, 25 fps, 1300 kbps main layer, 2 layers, higher bitrate for high motion. |
| H264_720P_30FPS_1_LAYER_HIGH_MOTION | 8 | 1280×720, 30 fps, 2500 kbps, no simulcast, higher bitrate for high motion. |
| H264_1080P_30FPS_1_LAYER_HIGH_MOTION | 9 | 1920×1080, 30 fps, 4500 kbps, no simulcast, higher bitrate for high motion. |
IngressAudioEncodingOptions
Custom audio encoding options.
| Field | Type | Description |
|---|---|---|
| audio_codec | AudioCodec | Desired audio codec to publish to the room. |
| bitrate | uint32 | Bitrate in bps. |
| disable_dtx | bool | Whether to disable DTX. |
| channels | uint32 | Number of channels. |
IngressVideoEncodingOptions
Custom video encoding options.
| Field | Type | Description |
|---|---|---|
| video_codec | VideoCodec | Desired video codec to publish to the room. |
| frame_rate | double | Frame rate. |
| layers | array<VideoLayer> | Simulcast layers. When empty, layers are typically set to 1/2 and 1/4 of dimensions. |