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

# Pull a broadcast source into a video room via RTMP/WHIP ingress

> Bring an OBS session, hardware encoder, or IP camera into a scheduled Orbit video room as a participant by creating an RTMP or WHIP ingress, then tear it down when the feed is done.

Egress pushes your room out to a streaming destination; ingress does the inverse. It pulls an external producer into a scheduled video room as a synthetic participant, so a broadcast encoder joins the room the way a person would: with a tile in the grid, a name in the roster, and a track in every composite, recording, and egress. Use it for hybrid town halls with a house camera run through vMix, field reporters pushing from a hardware encoder, or an OBS scene that shares the room with interactive WebRTC speakers.

This guide covers the three ingress types on `POST /api/v1/video/rooms-scheduled/{id}/ingress` (`createVideoRoomsScheduledByIdIngress` in the [video API reference](/api-reference/endpoints/video)): `rtmp` for standard broadcast encoders, `whip` for WebRTC-native uplinks, and `url` for sources Orbit should pull server-side.

## What an ingress gives you

Creating an ingress returns the credentials your encoder needs, once:

```json theme={null}
{
  "data": {
    "ingress_id": "IN_abcdefghijklmnop",
    "type": "rtmp",
    "stream_url": "<ingest endpoint for this ingress>",
    "stream_key": "<secret key, shown only here>",
    "participant_identity": "ingress_3f9c2ab1_kq82mz41",
    "created_at": "2026-10-12T09:00:00.000Z"
  }
}
```

* **RTMP ingress:** point any RTMP-capable encoder at `stream_url` with `stream_key` as the stream key. Orbit remuxes the push into the room's WebRTC media.
* **WHIP ingress:** `stream_url` is a WHIP (WebRTC-HTTP Ingestion Protocol) endpoint and `stream_key` is the bearer token for it. The media stays WebRTC end to end.
* **URL ingress:** you hand Orbit a public `http(s)://` or `rtmp(s)://` source (an HLS playlist, DASH manifest, or RTMP stream) and the media plane pulls it; no encoder configuration at all. `url` is required for `type: "url"` and rejected for the other two types.

The source joins under a server-generated `participant_identity` prefixed `ingress_`, so your roster always tells an ingested feed apart from a human participant. `name` (your internal label, e.g. "Main Stage OBS") and `participant_name` (the tile label attendees see) are optional at create time.

The `stream_key` is shown only in the create response and is never stored or retrievable afterwards. It stays valid until you delete the ingress or the room ends. If you lose it, delete the ingress and create a new one.

## Prerequisites

* **A scheduled room id.** Ingress endpoints hang off `/api/v1/video/rooms-scheduled/{id}`, the same surface as [HLS/DASH egress](/guides/video-room-hls-dash-egress) and [RTMP simulcast](/guides/video-rtmp-egress-simulcast). Ad-hoc rooms are not supported.
* **A host-tier credential.** Creating, listing, and deleting ingress requires an owner or admin role and an API key with the `video:write` scope. A key without that scope gets a 403.
* **An encoder.** For RTMP: OBS Studio 27 or newer, vMix, any hardware RTMP encoder, or an IP camera with RTMP push. For WHIP: a WHIP-capable client such as Larix Broadcaster or OBS with a WHIP output, or a command-line WHIP publisher for scripted feeds.
* **A public source, for `url` ingress.** The pull URL must be reachable from the public internet; private, loopback, and link-local addresses are rejected at validation.

## Create an ingress

```bash theme={null}
curl -X POST "https://orbit.devotel.io/api/v1/video/rooms-scheduled/$ROOM_ID/ingress" \
  -H "Authorization: Bearer $ORBIT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "rtmp",
    "name": "Main Stage OBS",
    "participant_name": "Main Stage"
  }'
```

Store `ingress_id` (you need it for teardown) and copy `stream_url` and `stream_key` into your encoder before closing the response; the key cannot be fetched again.

If the call fails:

* **403** means the caller lacks the owner/admin role or the `video:write` scope.
* **404** means the id is not a scheduled room in this tenant.
* **422** means the body failed validation: `url` is only accepted with `type: "url"`, must start with `http(s)://` or `rtmp(s)://`, and must be a public address.
* **503** means the video media plane is not configured for your tenant yet.

## Push from OBS over RTMP

1. Create the ingress with `"type": "rtmp"` as above.
2. In OBS, open **Settings → Stream** and set:
   * **Service:** Custom
   * **Server:** the `stream_url` from the create response
   * **Stream key:** the `stream_key` from the create response
3. In **Settings → Output**, send H.264 video and AAC audio, constant bitrate, with a 2-second keyframe interval (4,500 to 6,000 kbps suits 1080p30). Orbit transcodes RTMP pushes by default (`enable_transcoding` defaults to true for RTMP), but a clean H.264+AAC input keeps quality up and re-encodes cheaper.
4. Press **Start Streaming**.

Verify the feed landed:

* OBS's status dock shows a live bitrate and frame rate instead of "disconnected."
* The room gains a participant tile labelled with your `participant_name`.
* `GET /api/v1/video/rooms-scheduled/{id}/ingress` (`listVideoRoomsScheduledByIdIngress`) lists the ingress with its id, type, and creation time, without ever echoing the key.

If OBS reports a connection refusal, re-check that the server field holds `stream_url` exactly (no trailing slash, no key appended) and that the key was copied from the same create response.

## Push over WHIP

Create the ingress with `"type": "whip"`. The response is the same shape; for WHIP clients the two values map to:

* **WHIP endpoint URL:** `stream_url`
* **Authorization header:** `Bearer <stream_key>`

Configure those in your WHIP client (Larix Broadcaster, an OBS WHIP output, or a scripted WHIP publisher) and start the broadcast. Because WHIP carries WebRTC media natively, `enable_transcoding` defaults to false and nothing is remuxed: expect glass-to-glass latency well under a second, where an RTMP push typically adds a few seconds of pipeline delay. Pick WHIP when the feed joins an interactive scene and lip-sync with WebRTC speakers matters; pick RTMP when the source is broadcast hardware that only speaks RTMP. You can set `enable_transcoding` explicitly on either type if your source deviates from those defaults.

## Pull an existing source with `url`

When the feed already lives somewhere public (a partner's HLS stream, a camera's RTMP push URL, a DASH manifest), skip the encoder entirely:

```bash theme={null}
curl -X POST "https://orbit.devotel.io/api/v1/video/rooms-scheduled/$ROOM_ID/ingress" \
  -H "Authorization: Bearer $ORBIT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "url",
    "url": "https://feeds.example.com/camera1/playlist.m3u8",
    "participant_name": "Field Camera"
  }'
```

Orbit's media plane fetches the source and publishes it into the room; the create response still returns an `ingress_id` and `participant_identity`, but the `stream_key` is empty because there is nothing to authenticate on your side.

## Mix ingress with interactive participants

Ingress and WebRTC participants coexist without configuration. Speakers, moderators, and panelists join with ordinary access tokens (see [video room access tokens](/guides/video-room-access-tokens)); the ingested source arrives as one more publisher. Because its identity starts with `ingress_`, host tools can single it out: spotlight it in a layout, feature it in the speaker composite, or leave it as a grid tile. Recordings, HLS/DASH egresses, and [RTMP simulcast](/guides/video-rtmp-egress-simulcast) all include it exactly as they include human publishers.

If the encoder stops pushing, the rest of the room is unaffected: speakers keep talking and egresses keep writing. The ingress tile stops updating and the participant eventually leaves the roster. The feed does not resume on its own; start the encoder again against the same `stream_url` and `stream_key`, or delete the ingress and create a fresh one. Ingress creation and teardown are recorded in the room's activity trail, so [video room history](/guides/video-room-history) shows when each feed joined and left.

## Teardown and explicit disconnect

Delete an ingress by handle when the feed is done:

```bash theme={null}
curl -X DELETE "https://orbit.devotel.io/api/v1/video/rooms-scheduled/$ROOM_ID/ingress/$INGRESS_ID" \
  -H "Authorization: Bearer $ORBIT_API_KEY"
```

The call returns 204 and is idempotent: deleting an already-deleted ingress is safe, so retry logic and double-clicks never error. `GET /api/v1/video/rooms-scheduled/{id}/ingress` lists what is still active (`deleteVideoRoomsScheduledByIdIngressByIngressId` removes one). When the room ends, any remaining ingresses are reaped with it.

Tear ingresses down as soon as the feed is finished. A live ingress consumes media-plane capacity and, when paired with recording or egress, storage and bandwidth, until it stops.

## Pair ingress with HLS/DASH distribution

A common topology for hybrid events: ingest the external feed with this guide, then serve the passive audience over HLS or DASH from your CDN while a handful of hosts stay interactive on WebRTC. The [HLS/DASH egress guide](/guides/video-room-hls-dash-egress) covers the distribution half; the composite it broadcasts already includes your ingress source. If the destination is a third-party platform instead, use [RTMP simulcast](/guides/video-rtmp-egress-simulcast).

When a feed misbehaves (frozen tile, audio drift, dropped frames), the diagnostics surface is the same as for any participant: [video room media diagnostics](/guides/video-room-media-diagnostics) reports per-participant bitrate, codec, and packet stats, and the ingress participant is listed there under its `ingress_` identity.

## Related

* [Serve a video room as an HLS or DASH livestream with DVR](/guides/video-room-hls-dash-egress)
* [Simulcast a video room to RTMP platforms](/guides/video-rtmp-egress-simulcast)
* [Video room media diagnostics](/guides/video-room-media-diagnostics)
* [Video room history](/guides/video-room-history)
* [WHEP guest player](/guides/whep-guest-player)
* [Video room access tokens](/guides/video-room-access-tokens)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.