From a54b7101478d19eb6bd02dc4196a31f5c3b13275 Mon Sep 17 00:00:00 2001 From: David Zhao Date: Thu, 9 Jul 2026 01:33:01 +0200 Subject: [PATCH 1/2] readme updates will merge after api release --- livekit-api/README.md | 138 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 137 insertions(+), 1 deletion(-) diff --git a/livekit-api/README.md b/livekit-api/README.md index afcf79cd9..8c12b6a15 100644 --- a/livekit-api/README.md +++ b/livekit-api/README.md @@ -2,4 +2,140 @@ The official server API crate for [LiveKit](https://livekit.com). -Use this crate to generate access tokens and invoke LiveKit server APIs for agent dispatch, ingress, egress, SIP, and more. +Use this crate to generate access tokens and invoke LiveKit server APIs for rooms, egress, ingress, SIP, agent dispatch, and more. + +## Server API + +`LiveKitApi` is a single entry point to every server API, exposing each service through an accessor (`room()`, `egress()`, `ingress()`, `sip()`, `agent_dispatch()`, `connector()`). + +```rust,no_run +use livekit_api::services::LiveKitApi; +use livekit_api::services::room::CreateRoomOptions; + +#[tokio::main] +async fn main() -> Result<(), Box> { + let lk = LiveKitApi::with_api_key("https://my.livekit.host", "my-key", "my-secret"); + + let room = lk + .room() + .create_room( + "my-room", + CreateRoomOptions { empty_timeout: 600, max_participants: 20, ..Default::default() }, + ) + .await?; + + println!("created room {}", room.name); + Ok(()) +} +``` + +Individual service clients (`RoomClient`, `SIPClient`, etc.) can also be created directly with the same constructors. + +### Authentication + +The server API supports two modes of operation: + +- **API key & secret** — recommended for backend use. `LiveKitApi::with_api_key(host, key, secret)` signs a short-lived token for each request. `LiveKitApi::new(host)` reads the key and secret from the `LIVEKIT_API_KEY` and `LIVEKIT_API_SECRET` environment variables. +- **Access token** — for client-side use where the API secret must not be exposed. `LiveKitApi::with_token(host, token)` sends a pre-signed [access token](https://docs.livekit.io/frontends/reference/tokens-grants/) verbatim on every request; its grants must cover the calls you make. + +### Agent dispatch + +Explicitly dispatch an agent into a room (see [Agent dispatch](https://docs.livekit.io/agents/server/agent-dispatch/)): + +```rust,no_run +use livekit_api::services::LiveKitApi; +use livekit_protocol as proto; + +#[tokio::main] +async fn main() -> Result<(), Box> { + let lk = LiveKitApi::with_api_key("https://my.livekit.host", "my-key", "my-secret"); + + lk.agent_dispatch() + .create_dispatch(proto::CreateAgentDispatchRequest { + room: "my-room".to_owned(), + agent_name: "my-agent".to_owned(), + ..Default::default() + }) + .await?; + Ok(()) +} +``` + +### Error handling + +Service methods return `ServiceResult` (`Result`). A failed server call is a `ServiceError::Twirp(ServerError)`; when the server returns a structured error it is `ServerError::Twirp(ServerErrorCode)`, which carries the error code and message. (`ServerError`'s former `TwirpError`/`TwirpErrorCode`/`TwirpResult` type names remain as deprecated aliases.) + +```rust,no_run +use livekit_api::services::LiveKitApi; + +#[tokio::main] +async fn main() { + let lk = LiveKitApi::with_api_key("https://my.livekit.host", "my-key", "my-secret"); + match lk.room().delete_room("my-room").await { + Ok(_) => {} + Err(e) => eprintln!("delete_room failed: {e}"), + } +} +``` + +### Handling SIP call errors + +When a SIP call fails (e.g. the callee is busy or declines), the server attaches a SIP status to the error. `SipCallError::from_error` decodes it from a returned error, exposing the SIP status code and reason: + +```rust,no_run +use livekit_api::services::sip::CreateSIPParticipantOptions; +use livekit_api::services::{LiveKitApi, SipCallError}; + +#[tokio::main] +async fn main() { + let lk = LiveKitApi::with_api_key("https://my.livekit.host", "my-key", "my-secret"); + + let result = lk + .sip() + .create_sip_participant( + "ST_trunk".to_owned(), + "+15105550100".to_owned(), + "my-room".to_owned(), + CreateSIPParticipantOptions { + wait_until_answered: Some(true), + ..Default::default() + }, + None, + ) + .await; + + if let Err(err) = result { + if let Some(sip) = SipCallError::from_error(&err) { + eprintln!("{sip}"); // e.g. "SIP call failed: 486 Busy Here (resource_exhausted)" + if sip.sip_status_code() == Some(486) { + // callee is busy + } + } + } +} +``` + +## Access tokens + +Access tokens are generated with `AccessToken`: + +```rust,no_run +use livekit_api::access_token::{AccessToken, VideoGrants}; + +fn main() -> Result<(), Box> { + let token = AccessToken::with_api_key("my-key", "my-secret") + .with_identity("participant-identity") + .with_name("Participant Name") + .with_grants(VideoGrants { + room_join: true, + room: "my-room".to_owned(), + ..Default::default() + }) + .to_jwt()?; + + println!("{token}"); + Ok(()) +} +``` + +By default, tokens expire 6 hours after generation. Override this with `.with_ttl(duration)`. From efa7cd44e45b2fe5a9e5c6b23c7f8215c6326a9d Mon Sep 17 00:00:00 2001 From: David Zhao Date: Fri, 10 Jul 2026 16:40:38 +0200 Subject: [PATCH 2/2] updates --- livekit-api/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/livekit-api/README.md b/livekit-api/README.md index 8c12b6a15..ff6607feb 100644 --- a/livekit-api/README.md +++ b/livekit-api/README.md @@ -35,7 +35,7 @@ Individual service clients (`RoomClient`, `SIPClient`, etc.) can also be created The server API supports two modes of operation: -- **API key & secret** — recommended for backend use. `LiveKitApi::with_api_key(host, key, secret)` signs a short-lived token for each request. `LiveKitApi::new(host)` reads the key and secret from the `LIVEKIT_API_KEY` and `LIVEKIT_API_SECRET` environment variables. +- **API key & secret** — recommended for backend use. `LiveKitApi::new(host)` reads the key and secret from the `LIVEKIT_API_KEY` and `LIVEKIT_API_SECRET` environment variables; `LiveKitApi::with_api_key(host, key, secret)` takes them explicitly instead. Either way, a short-lived token is signed for each request. - **Access token** — for client-side use where the API secret must not be exposed. `LiveKitApi::with_token(host, token)` sends a pre-signed [access token](https://docs.livekit.io/frontends/reference/tokens-grants/) verbatim on every request; its grants must cover the calls you make. ### Agent dispatch