In WHIP (RFC 9725), how does a WebRTC encoder publish a stream with one HTTP POST, and what does the 201 Created response carry?
answer
- signalling fixed as plain HTTP
- application/sdp in both directions
- a session resource is created
- PATCH for ICE, DELETE to stop
- no renegotiation after the POST
basics
~20 sThe encoder POSTs its SDP offer as application/sdp to the WHIP endpoint URL. The endpoint replies 201 Created with the SDP answer as the body and a Location header naming the session resource, later used for PATCH (ICE updates) and DELETE (teardown).
solid answer
~50 sWHIP replaces the open-ended signalling channel with HTTP. The client builds an initial JSEP offer (`sendonly`, bundled) and POSTs it with `Content-Type: application/sdp` to the WHIP endpoint URL; every WHIP entity must support bearer-token authentication in the `Authorization` header. The endpoint returns `201 Created` with the SDP answer (`recvonly`) as the body and a `Location` header pointing at the new WHIP session URL. If it supports ICE restarts it adds an `ETag` identifying the ICE session, and it may add `Link` headers with `rel="ice-server"` for STUN and TURN. After that only ICE can change: the client sends `PATCH` with an `application/trickle-ice-sdpfrag` body to trickle candidates or restart ICE, and `DELETE` on the session URL to end the stream. The server cannot trickle, so its answer holds all its candidates, and there is no SDP renegotiation: the `m=` sections are fixed by the POST.
code
http · 25 linesPOST /whip/studio-4 HTTP/1.1
Host: ingest.example.com
Authorization: Bearer <token>
Content-Type: application/sdp
v=0
o=- 4611731400430051336 2 IN IP4 127.0.0.1
s=-
t=0 0
a=group:BUNDLE 0 1
a=ice-options:trickle ice2
m=audio 9 UDP/TLS/RTP/SAVPF 111
a=mid:0
a=sendonly
m=video 0 UDP/TLS/RTP/SAVPF 96
a=mid:1
a=bundle-only
a=sendonly
HTTP/1.1 201 Created
Location: https://ingest.example.com/whip/session/7f3a
ETag: "a1"
Content-Type: application/sdp
<SDP answer: the same two m= sections, each a=recvonly>go deeper
Recall that WHIP turns WebRTC signalling into one HTTP POST of an SDP offer, answered with 201 Created, the SDP answer and a Location URL.
Explain what follows the POST: PATCH with trickle-ice-sdpfrag for candidates or restarts, DELETE to end, and why the server never trickles.
Show you know the operational edges: no renegotiation, entity-tag preconditions on trickle PATCHes, 307 rather than 301 or 302, bearer tokens and 422 for unsupported layouts.
Weigh standard WHIP ingest against custom signalling for a broadcast product, trading encoder interoperability against WHIP's fixed one-way, one-stream session shape.
## What WHIP fixes that JSEP leaves open JSEP (RFC 9429) produces and applies SDP offers and answers but leaves their transport to the application. That freedom is a cost for **broadcast ingest**: every encoder would need custom signalling for every streaming service. The **WebRTC-HTTP Ingestion Protocol** (WHIP, RFC 9725) fixes the signalling as plain HTTP. It is a "one-time exchange" of an SDP offer and answer by HTTP POST, followed by unidirectional media from the **WHIP client** (the encoder) to a **media server**. ## The exchange, step by step 1. The client generates an offer by JSEP's rules for an initial offer. Media flows one way, so it SHOULD mark sections `sendonly` (it MAY use `sendrecv`; `inactive` and `recvonly` are forbidden). 2. It sends `POST` to the configured **WHIP endpoint URL** with `Content-Type: application/sdp` and the offer as the body. 3. The endpoint generates an answer by JSEP's rules for an initial answer, marked `recvonly`, and returns `201 Created`. 4. ICE connectivity checks and the DTLS handshake run between client and media server, then SRTP-protected RTP flows. 5. To stop, the client MUST send `DELETE` to the **WHIP session URL**. Consent freshness (RFC 7675) detects a non-graceful disconnection. A wrong content type or malformed SDP gets a 4xx response. ## The 201 response, header by header | Part | Requirement | Purpose | |---|---|---| | status `201 Created` | MUST | a new session resource exists | | body, `Content-Type: application/sdp` | MUST | the SDP answer | | `Location` | MUST | the WHIP session URL for later PATCH and DELETE | | `ETag` | MUST if ICE restarts are supported | a strong entity-tag identifying the current ICE session | | `Link: <...>; rel="ice-server"` | MAY | STUN/TURN URIs (RFC 7064 / 7065) and credentials for the client | ## After the POST: only ICE may change - **Trickle.** The client cannot trickle until it knows the session URL, so it buffers candidates until the `201` arrives, then SHOULD send one aggregated `PATCH` with an `application/trickle-ice-sdpfrag` body. A PATCH that only adds candidates gets `204 No Content`. - **Entity-tags.** Trickle PATCHes are conditional requests: `If-Match` carries the current ICE session's entity-tag. A missing tag gets `428 Precondition Required` and a non-matching one `412 Precondition Failed`. - **ICE restart.** A `PATCH` carrying a new `ice-ufrag` and `ice-pwd` with `If-Match: "*"`; the session answers `200 OK` with its own new credentials and candidates and a new `ETag`. - **Partial support.** A session that supports trickle or restart but not both answers the unsupported kind of PATCH with `422 Unprocessable Content`. - **No server trickle.** The WHIP session cannot send candidates after the answer, so the endpoint gathers all of the media server's candidates before responding. - **No renegotiation.** The `m=` sections cannot change after the POST. A client that needs a different layout ends the session and starts a new one. ## Constraints WHIP adds to WebRTC To keep clients and servers simple, RFC 9725 narrows what may be offered: - **BUNDLE** with RTP/RTCP multiplexing for all media, and `a=rtcp-mux-only` in each bundled section. - **One MediaStream**, with at least one track and never two tracks of the same kind; an unsupported layout is rejected with `422` or `400`. - **No partially successful answers**: rather than rejecting individual `m=` sections, the endpoint SHOULD reject the whole POST. - **Full ICE** on the client; the media server MAY be ICE lite when every authorized client can reach its address directly. ## Operating it - **Authentication.** WHIP entities MUST support HTTP authentication, and bearer tokens in the `Authorization` header in particular, for interoperability. - **Load balancing.** Clients SHALL follow redirects. `301` and `302` MUST NOT be used, because clients may resend a redirected POST as a GET; `307 Temporary Redirect` is preferred. Under overload an endpoint MAY answer `503` with `Retry-After`. - **CORS.** Endpoints MUST support `OPTIONS`, so browser-based clients can POST cross-origin. ## Common misreadings - Expecting `200 OK`: the session is a created resource, so it is `201` plus `Location`. - Expecting the server to trickle: its candidates all arrive in the answer. - Adding a track by PATCH: PATCH carries ICE fragments only, never new `m=` sections. - Ending a stream by dropping the connection: the client MUST send `DELETE`.
- Why does WHIP (RFC 9725) forbid 301 and 302 when load-balancing ingest across servers?Because HTTP clients may turn a redirected POST into a GET, losing the SDP offer in the body. RFC 9725 says 301 and 302 MUST NOT be used and prefers `307 Temporary Redirect`, which preserves method and body. Clients SHALL support redirects for the POST; redirects for PATCH and DELETE are not required.
- A WHIP encoder needs to add a second video track mid-stream. What are its options?Within the session, none: RFC 9725 forbids SDP renegotiation, so the `m=` sections are fixed after the POST, and it allows only one MediaStream with at most one track per kind. The client must `DELETE` the session and POST a new offer, and the endpoint must reject layouts it does not support.
- How does a WHIP client trickle candidates gathered before the 201 response arrives?It buffers them, because it does not yet know the session URL (or, with ICE restarts, the entity-tag). Once the `201 Created` arrives it SHOULD send one aggregated PATCH with an `application/trickle-ice-sdpfrag` body; the session replies `204 No Content` when the PATCH only adds candidates.
saying these in an interview costs you the question
- WHIP answers the POST with 200 OK and the SDP answer.
- The WHIP server trickles its candidates to the client later.
- A WHIP client adds a track by PATCHing a new m= section.
- A WHIP stream ends just by closing the peer connection.
- A 302 redirect is fine for spreading WHIP load.