Skip to main content

livekit_api/services/
livekit_api.rs

1// Copyright 2026 LiveKit, Inc.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use std::time::Duration;
16
17use super::agent_dispatch::AgentDispatchClient;
18use super::connector::ConnectorClient;
19use super::databases::DatabaseClient;
20use super::egress::EgressClient;
21use super::ingress::IngressClient;
22use super::room::RoomClient;
23use super::sip::SIPClient;
24use super::threads::ThreadClient;
25use super::{ServiceBase, ServiceResult};
26use crate::http_client;
27use livekit_token::get_env_keys;
28
29/// A single entry point to every LiveKit server API, exposing each service
30/// through an accessor (`room()`, `egress()`, `ingress()`, `sip()`,
31/// `agent_dispatch()`, `connector()`, `threads()`, `databases()`).
32///
33/// Construct it with an API key and secret ([`with_api_key`](Self::with_api_key),
34/// or [`new`](Self::new) to read them from the environment) for backend use, or
35/// with a pre-signed token ([`with_token`](Self::with_token)) for client-side use
36/// where the API secret must not be exposed.
37#[derive(Debug)]
38pub struct LiveKitApi {
39    room: RoomClient,
40    egress: EgressClient,
41    ingress: IngressClient,
42    sip: SIPClient,
43    agent_dispatch: AgentDispatchClient,
44    connector: ConnectorClient,
45    threads: ThreadClient,
46    databases: DatabaseClient,
47}
48
49impl LiveKitApi {
50    pub fn with_api_key(host: &str, api_key: &str, api_secret: &str) -> Self {
51        // One HTTP client shared across every service, so they reuse a single
52        // connection pool instead of each opening its own.
53        let http = http_client::client();
54        let base = || ServiceBase::with_api_key(api_key, api_secret);
55        Self {
56            room: RoomClient::build(host, base(), http.clone()),
57            egress: EgressClient::build(host, base(), http.clone()),
58            ingress: IngressClient::build(host, base(), http.clone()),
59            sip: SIPClient::build(host, base(), http.clone()),
60            agent_dispatch: AgentDispatchClient::build(host, base(), http.clone()),
61            connector: ConnectorClient::build(host, base(), http.clone()),
62            threads: ThreadClient::build(host, base(), http.clone()),
63            databases: DatabaseClient::build(host, base(), http),
64        }
65    }
66
67    /// Reads the key and secret from the `LIVEKIT_API_KEY` and
68    /// `LIVEKIT_API_SECRET` environment variables.
69    pub fn new(host: &str) -> ServiceResult<Self> {
70        let (api_key, api_secret) = get_env_keys()?;
71        Ok(Self::with_api_key(host, &api_key, &api_secret))
72    }
73
74    /// Authenticates with a pre-signed token, sent verbatim on every request.
75    /// The token's grants must cover the calls made through this client.
76    pub fn with_token(host: &str, token: &str) -> Self {
77        // One HTTP client shared across every service (see `with_api_key`).
78        let http = http_client::client();
79        let base = || ServiceBase::with_token(token);
80        Self {
81            room: RoomClient::build(host, base(), http.clone()),
82            egress: EgressClient::build(host, base(), http.clone()),
83            ingress: IngressClient::build(host, base(), http.clone()),
84            sip: SIPClient::build(host, base(), http.clone()),
85            agent_dispatch: AgentDispatchClient::build(host, base(), http.clone()),
86            connector: ConnectorClient::build(host, base(), http.clone()),
87            threads: ThreadClient::build(host, base(), http.clone()),
88            databases: DatabaseClient::build(host, base(), http),
89        }
90    }
91
92    /// Enables or disables region failover on every service (enabled by
93    /// default). Failover only engages for LiveKit Cloud hosts.
94    pub fn with_failover(mut self, enabled: bool) -> Self {
95        self.room = self.room.with_failover(enabled);
96        self.egress = self.egress.with_failover(enabled);
97        self.ingress = self.ingress.with_failover(enabled);
98        self.sip = self.sip.with_failover(enabled);
99        self.agent_dispatch = self.agent_dispatch.with_failover(enabled);
100        self.connector = self.connector.with_failover(enabled);
101        self
102    }
103
104    /// Overrides the default per-request timeout (10s) on every service.
105    pub fn with_request_timeout(mut self, timeout: Duration) -> Self {
106        self.room = self.room.with_request_timeout(timeout);
107        self.egress = self.egress.with_request_timeout(timeout);
108        self.ingress = self.ingress.with_request_timeout(timeout);
109        self.sip = self.sip.with_request_timeout(timeout);
110        self.agent_dispatch = self.agent_dispatch.with_request_timeout(timeout);
111        self.connector = self.connector.with_request_timeout(timeout);
112        self.threads = self.threads.with_request_timeout(timeout);
113        self.databases = self.databases.with_request_timeout(timeout);
114        self
115    }
116
117    /// Injects a mock-control header on every service (see the mock test server's
118    /// X-Lk-Mock protocol). Test-only, since the service methods don't expose
119    /// per-call headers.
120    #[cfg(test)]
121    pub(crate) fn with_mock(mut self, mock: &str) -> Self {
122        let mut headers = http::HeaderMap::new();
123        headers.insert(
124            http::HeaderName::from_static("x-lk-mock"),
125            http::HeaderValue::from_str(mock).unwrap(),
126        );
127        self.room = self.room.with_default_headers(headers.clone());
128        self.egress = self.egress.with_default_headers(headers.clone());
129        self.ingress = self.ingress.with_default_headers(headers.clone());
130        self.sip = self.sip.with_default_headers(headers.clone());
131        self.agent_dispatch = self.agent_dispatch.with_default_headers(headers.clone());
132        self.connector = self.connector.with_default_headers(headers);
133        self
134    }
135
136    pub fn room(&self) -> &RoomClient {
137        &self.room
138    }
139
140    pub fn egress(&self) -> &EgressClient {
141        &self.egress
142    }
143
144    pub fn ingress(&self) -> &IngressClient {
145        &self.ingress
146    }
147
148    pub fn sip(&self) -> &SIPClient {
149        &self.sip
150    }
151
152    pub fn agent_dispatch(&self) -> &AgentDispatchClient {
153        &self.agent_dispatch
154    }
155
156    pub fn connector(&self) -> &ConnectorClient {
157        &self.connector
158    }
159
160    pub fn threads(&self) -> &ThreadClient {
161        &self.threads
162    }
163
164    pub fn databases(&self) -> &DatabaseClient {
165        &self.databases
166    }
167}